diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/index.js b/src/core/math/index.js index fd0d9be..a43f6e7 100644 --- a/src/core/math/index.js +++ b/src/core/math/index.js @@ -11,6 +11,7 @@ Point: require('./Point'), Matrix: require('./Matrix'), + GroupD8: require('./GroupD8'), Circle: require('./shapes/Circle'), Ellipse: require('./shapes/Ellipse'), diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/index.js b/src/core/math/index.js index fd0d9be..a43f6e7 100644 --- a/src/core/math/index.js +++ b/src/core/math/index.js @@ -11,6 +11,7 @@ Point: require('./Point'), Matrix: require('./Matrix'), + GroupD8: require('./GroupD8'), Circle: require('./shapes/Circle'), Ellipse: require('./shapes/Ellipse'), diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7440a0f..ae1fd1b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -4,7 +4,9 @@ CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), - tempPoint = new math.Point(); + tempPoint = new math.Point(), + GroupD8 = math.GroupD8, + canvasRenderWorldTransform = new math.Matrix(); /** * The Sprite object is the base for all textured objects that are rendered to the screen @@ -266,7 +268,7 @@ else { */ - + var x1 = a * w1 + c * h1 + tx; var y1 = d * h1 + b * w1 + ty; @@ -412,45 +414,25 @@ renderer.context[renderer.smoothProperty] = smoothingEnabled; } + //texture can be rotated, that's serious! + var swapWidthHeight = GroupD8.isSwapWidthHeight(texture.rotate); + width = swapWidthHeight ? texture.crop.height : texture.crop.width; + height = swapWidthHeight ? texture.crop.width : texture.crop.height; + // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions + dx = (texture.trim) ? texture.trim.x - (this.anchor.x - 0.5) * texture.trim.width : (this.anchor.x - 0.5) * -texture._frame.width; + dy = (texture.trim) ? texture.trim.y - (this.anchor.y - 0.5) * texture.trim.height : (this.anchor.y - 0.5) * -texture._frame.height; - if(texture.rotate) - { - width = texture.crop.height; - height = texture.crop.width; - - dx = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - dy = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - - dx += width; - - wt.tx = dy * wt.a + dx * wt.c + wt.tx; - wt.ty = dy * wt.b + dx * wt.d + wt.ty; - - var temp = wt.a; - wt.a = -wt.c; - wt.c = temp; - - temp = wt.b; - wt.b = -wt.d; - wt.d = temp; - + if(texture.rotate) { + wt.copy(canvasRenderWorldTransform); + wt = canvasRenderWorldTransform; + GroupD8.appendRotationInv(wt, texture.rotate, dx, dy); // the anchor has already been applied above, so lets set it to zero dx = 0; dy = 0; - } - else - { - width = texture.crop.width; - height = texture.crop.height; - - dx = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - dy = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - } - - - + dx -= width/2; + dy -= height/2; // Allow for pixel rounding if (renderer.roundPixels) { diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/index.js b/src/core/math/index.js index fd0d9be..a43f6e7 100644 --- a/src/core/math/index.js +++ b/src/core/math/index.js @@ -11,6 +11,7 @@ Point: require('./Point'), Matrix: require('./Matrix'), + GroupD8: require('./GroupD8'), Circle: require('./shapes/Circle'), Ellipse: require('./shapes/Ellipse'), diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7440a0f..ae1fd1b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -4,7 +4,9 @@ CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), - tempPoint = new math.Point(); + tempPoint = new math.Point(), + GroupD8 = math.GroupD8, + canvasRenderWorldTransform = new math.Matrix(); /** * The Sprite object is the base for all textured objects that are rendered to the screen @@ -266,7 +268,7 @@ else { */ - + var x1 = a * w1 + c * h1 + tx; var y1 = d * h1 + b * w1 + ty; @@ -412,45 +414,25 @@ renderer.context[renderer.smoothProperty] = smoothingEnabled; } + //texture can be rotated, that's serious! + var swapWidthHeight = GroupD8.isSwapWidthHeight(texture.rotate); + width = swapWidthHeight ? texture.crop.height : texture.crop.width; + height = swapWidthHeight ? texture.crop.width : texture.crop.height; + // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions + dx = (texture.trim) ? texture.trim.x - (this.anchor.x - 0.5) * texture.trim.width : (this.anchor.x - 0.5) * -texture._frame.width; + dy = (texture.trim) ? texture.trim.y - (this.anchor.y - 0.5) * texture.trim.height : (this.anchor.y - 0.5) * -texture._frame.height; - if(texture.rotate) - { - width = texture.crop.height; - height = texture.crop.width; - - dx = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - dy = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - - dx += width; - - wt.tx = dy * wt.a + dx * wt.c + wt.tx; - wt.ty = dy * wt.b + dx * wt.d + wt.ty; - - var temp = wt.a; - wt.a = -wt.c; - wt.c = temp; - - temp = wt.b; - wt.b = -wt.d; - wt.d = temp; - + if(texture.rotate) { + wt.copy(canvasRenderWorldTransform); + wt = canvasRenderWorldTransform; + GroupD8.appendRotationInv(wt, texture.rotate, dx, dy); // the anchor has already been applied above, so lets set it to zero dx = 0; dy = 0; - } - else - { - width = texture.crop.width; - height = texture.crop.height; - - dx = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - dy = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - } - - - + dx -= width/2; + dy -= height/2; // Allow for pixel rounding if (renderer.roundPixels) { diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index e43e8b5..41f5313 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -23,7 +23,7 @@ * @param [frame] {PIXI.Rectangle} The rectangle frame of the texture to show * @param [crop] {PIXI.Rectangle} The area of original texture * @param [trim] {PIXI.Rectangle} Trimmed texture rectangle - * @param [rotate] {boolean} indicates whether the texture should be rotated by 90 degrees ( used by texture packer ) + * @param [rotate] {number} indicates how the texture was rotated by texture packer. See {@link PIXI.GroupD8} */ function Texture(baseTexture, frame, crop, trim, rotate) { @@ -113,13 +113,14 @@ */ this.crop = crop || frame;//new math.Rectangle(0, 0, 1, 1); - /** - * Indicates whether the texture should be rotated by 90 degrees - * - * @private - * @member {boolean} - */ - this.rotate = !!rotate; + this._rotate = +(rotate || 0); + + if (rotate === true) { + // this is old texturepacker legacy, some games/libraries are passing "true" or 1 for rotated textures + this._rotate = 2; + } else if (this.rotate % 2 !== 0) { + throw 'Texture rotation must be divisible by 2'; + } if (baseTexture.hasLoaded) { @@ -196,6 +197,29 @@ this._updateUvs(); } } + }, + /** + * Indicates whether the texture is rotated inside the atlas + * set to 2 to compensate for texture packer rotation + * set to 6 to compensate for spine packer rotation + * can be used to rotate or mirror sprites + * See {@link PIXI.GroupD8} for explanation + * + * @member {number} + */ + rotate: { + get: function () + { + return this._rotate; + }, + set: function (rotate) + { + this._rotate = rotate; + if (this.valid) + { + this._updateUvs(); + } + } } }); diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/index.js b/src/core/math/index.js index fd0d9be..a43f6e7 100644 --- a/src/core/math/index.js +++ b/src/core/math/index.js @@ -11,6 +11,7 @@ Point: require('./Point'), Matrix: require('./Matrix'), + GroupD8: require('./GroupD8'), Circle: require('./shapes/Circle'), Ellipse: require('./shapes/Ellipse'), diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7440a0f..ae1fd1b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -4,7 +4,9 @@ CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), - tempPoint = new math.Point(); + tempPoint = new math.Point(), + GroupD8 = math.GroupD8, + canvasRenderWorldTransform = new math.Matrix(); /** * The Sprite object is the base for all textured objects that are rendered to the screen @@ -266,7 +268,7 @@ else { */ - + var x1 = a * w1 + c * h1 + tx; var y1 = d * h1 + b * w1 + ty; @@ -412,45 +414,25 @@ renderer.context[renderer.smoothProperty] = smoothingEnabled; } + //texture can be rotated, that's serious! + var swapWidthHeight = GroupD8.isSwapWidthHeight(texture.rotate); + width = swapWidthHeight ? texture.crop.height : texture.crop.width; + height = swapWidthHeight ? texture.crop.width : texture.crop.height; + // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions + dx = (texture.trim) ? texture.trim.x - (this.anchor.x - 0.5) * texture.trim.width : (this.anchor.x - 0.5) * -texture._frame.width; + dy = (texture.trim) ? texture.trim.y - (this.anchor.y - 0.5) * texture.trim.height : (this.anchor.y - 0.5) * -texture._frame.height; - if(texture.rotate) - { - width = texture.crop.height; - height = texture.crop.width; - - dx = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - dy = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - - dx += width; - - wt.tx = dy * wt.a + dx * wt.c + wt.tx; - wt.ty = dy * wt.b + dx * wt.d + wt.ty; - - var temp = wt.a; - wt.a = -wt.c; - wt.c = temp; - - temp = wt.b; - wt.b = -wt.d; - wt.d = temp; - + if(texture.rotate) { + wt.copy(canvasRenderWorldTransform); + wt = canvasRenderWorldTransform; + GroupD8.appendRotationInv(wt, texture.rotate, dx, dy); // the anchor has already been applied above, so lets set it to zero dx = 0; dy = 0; - } - else - { - width = texture.crop.width; - height = texture.crop.height; - - dx = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - dy = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - } - - - + dx -= width/2; + dy -= height/2; // Allow for pixel rounding if (renderer.roundPixels) { diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index e43e8b5..41f5313 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -23,7 +23,7 @@ * @param [frame] {PIXI.Rectangle} The rectangle frame of the texture to show * @param [crop] {PIXI.Rectangle} The area of original texture * @param [trim] {PIXI.Rectangle} Trimmed texture rectangle - * @param [rotate] {boolean} indicates whether the texture should be rotated by 90 degrees ( used by texture packer ) + * @param [rotate] {number} indicates how the texture was rotated by texture packer. See {@link PIXI.GroupD8} */ function Texture(baseTexture, frame, crop, trim, rotate) { @@ -113,13 +113,14 @@ */ this.crop = crop || frame;//new math.Rectangle(0, 0, 1, 1); - /** - * Indicates whether the texture should be rotated by 90 degrees - * - * @private - * @member {boolean} - */ - this.rotate = !!rotate; + this._rotate = +(rotate || 0); + + if (rotate === true) { + // this is old texturepacker legacy, some games/libraries are passing "true" or 1 for rotated textures + this._rotate = 2; + } else if (this.rotate % 2 !== 0) { + throw 'Texture rotation must be divisible by 2'; + } if (baseTexture.hasLoaded) { @@ -196,6 +197,29 @@ this._updateUvs(); } } + }, + /** + * Indicates whether the texture is rotated inside the atlas + * set to 2 to compensate for texture packer rotation + * set to 6 to compensate for spine packer rotation + * can be used to rotate or mirror sprites + * See {@link PIXI.GroupD8} for explanation + * + * @member {number} + */ + rotate: { + get: function () + { + return this._rotate; + }, + set: function (rotate) + { + this._rotate = rotate; + if (this.valid) + { + this._updateUvs(); + } + } } }); diff --git a/src/core/textures/TextureUvs.js b/src/core/textures/TextureUvs.js index b3a5f7f..6bf607e 100644 --- a/src/core/textures/TextureUvs.js +++ b/src/core/textures/TextureUvs.js @@ -23,11 +23,13 @@ module.exports = TextureUvs; +var GroupD8 = require('../math/GroupD8'); + /** * Sets the texture Uvs based on the given frame information * @param frame {PIXI.Rectangle} * @param baseFrame {PIXI.Rectangle} - * @param rotate {boolean} Whether or not the frame is rotated + * @param rotate {int} Rotation of frame, see {@link PIXI.GroupD8} * @private */ TextureUvs.prototype.set = function (frame, baseFrame, rotate) @@ -37,17 +39,25 @@ if(rotate) { - this.x0 = (frame.x + frame.height) / tw; - this.y0 = frame.y / th; - - this.x1 = (frame.x + frame.height) / tw; - this.y1 = (frame.y + frame.width) / th; - - this.x2 = frame.x / tw; - this.y2 = (frame.y + frame.width) / th; - - this.x3 = frame.x / tw; - this.y3 = frame.y / th; + //width and height div 2 div baseFrame size + var swapWidthHeight = GroupD8.isSwapWidthHeight(rotate); + var w2 = (swapWidthHeight ? frame.height : frame.width) / 2 / tw; + var h2 = (swapWidthHeight ? frame.width : frame.height) / 2 / th; + //coordinates of center + var cX = frame.x / tw + w2; + var cY = frame.y / th + h2; + rotate = GroupD8.add(rotate, GroupD8.NW); //NW is top-left corner + this.x0 = cX + w2 * GroupD8.uX(rotate); + this.y0 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); //rotate 90 degrees clockwise + this.x1 = cX + w2 * GroupD8.uX(rotate); + this.y1 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); + this.x2 = cX + w2 * GroupD8.uX(rotate); + this.y2 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); + this.x3 = cX + w2 * GroupD8.uX(rotate); + this.y3 = cY + h2 * GroupD8.uY(rotate); } else { diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js new file mode 100644 index 0000000..31c5d5e --- /dev/null +++ b/src/core/math/GroupD8.js @@ -0,0 +1,150 @@ +var ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; +var uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; +var vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; +var tempMatrices = []; +var Matrix = require('./Matrix'); + +var mul = []; + +function signum(x) { + if (x < 0) { + return -1; + } + if (x > 0) { + return 1; + } + return 0; +} + +function init() { + for (var i = 0; i < 16; i++) { + var row = []; + mul.push(row); + for (var j = 0; j < 16; j++) { + var _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + var _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + var _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + var _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (var k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + + for (i=0;i<16;i++) { + var mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + tempMatrices.push(mat); + } +} + +init(); + +/** + * Implements Dihedral Group D_8, see [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html}, D8 is the same but with diagonals + * Used for texture rotations + * Vector xX(i), xY(i) is U-axis of sprite with rotation i + * Vector yY(i), yY(i) is V-axis of sprite with rotation i + * Rotations: 0 grad (0), 90 grad (2), 180 grad (4), 270 grad (6) + * Mirrors: vertical (8), main diagonal (10), horizontal (12), reverse diagonal (14) + * This is the small part of gameofbombs.com portal system. It works. + * @author Ivan @ivanpopelyshev + * + * @namespace PIXI.GroupD8 + */ +var GroupD8 = { + E: 0, + SE: 1, + S: 2, + SW: 3, + W: 4, + NW: 5, + N: 6, + NE: 7, + MIRROR_VERTICAL: 8, + MIRROR_HORIZONTAL: 10, + uX: function (ind) { + return ux[ind]; + }, + uY: function (ind) { + return uy[ind]; + }, + vX: function (ind) { + return vx[ind]; + }, + vY: function (ind) { + return vy[ind]; + }, + inv: function (rotation) { + if (rotation & 8) { + return rotation & 15; + } + return (-rotation) & 7; + }, + add: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][rotationFirst]; + }, + sub: function (rotationSecond, rotationFirst) { + return mul[rotationSecond][GroupD8.inv(rotationFirst)]; + }, + rotate180: function (rotation) { + return rotation ^ 8; + }, + isSwapWidthHeight: function(rotation) { + return (rotation & 3) === 2; + }, + byDirection: function (dx, dy) { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return GroupD8.S; + } + else { + return GroupD8.N; + } + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return GroupD8.E; + } + else { + return GroupD8.W; + } + } else { + if (dy > 0) { + if (dx > 0) { + return GroupD8.SE; + } + else { + return GroupD8.SW; + } + } + else if (dx > 0) { + return GroupD8.NE; + } + else { + return GroupD8.NW; + } + } + }, + /** + * Helps sprite to compensate texture packer rotation. + * @param matrix {PIXI.Matrix} sprite world matrix + * @param rotation {number} + * @param tx {number|*} sprite anchoring + * @param ty {number|*} sprite anchoring + */ + matrixAppendRotationInv: function (matrix, rotation, tx, ty) { + //Packer used "rotation", we use "inv(rotation)" + var mat = tempMatrices[GroupD8.inv(rotation)]; + tx = tx || 0; + ty = ty || 0; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } +}; + +module.exports = GroupD8; diff --git a/src/core/math/index.js b/src/core/math/index.js index fd0d9be..a43f6e7 100644 --- a/src/core/math/index.js +++ b/src/core/math/index.js @@ -11,6 +11,7 @@ Point: require('./Point'), Matrix: require('./Matrix'), + GroupD8: require('./GroupD8'), Circle: require('./shapes/Circle'), Ellipse: require('./shapes/Ellipse'), diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 7440a0f..ae1fd1b 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -4,7 +4,9 @@ CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), utils = require('../utils'), CONST = require('../const'), - tempPoint = new math.Point(); + tempPoint = new math.Point(), + GroupD8 = math.GroupD8, + canvasRenderWorldTransform = new math.Matrix(); /** * The Sprite object is the base for all textured objects that are rendered to the screen @@ -266,7 +268,7 @@ else { */ - + var x1 = a * w1 + c * h1 + tx; var y1 = d * h1 + b * w1 + ty; @@ -412,45 +414,25 @@ renderer.context[renderer.smoothProperty] = smoothingEnabled; } + //texture can be rotated, that's serious! + var swapWidthHeight = GroupD8.isSwapWidthHeight(texture.rotate); + width = swapWidthHeight ? texture.crop.height : texture.crop.width; + height = swapWidthHeight ? texture.crop.width : texture.crop.height; + // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions + dx = (texture.trim) ? texture.trim.x - (this.anchor.x - 0.5) * texture.trim.width : (this.anchor.x - 0.5) * -texture._frame.width; + dy = (texture.trim) ? texture.trim.y - (this.anchor.y - 0.5) * texture.trim.height : (this.anchor.y - 0.5) * -texture._frame.height; - if(texture.rotate) - { - width = texture.crop.height; - height = texture.crop.width; - - dx = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - dy = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - - dx += width; - - wt.tx = dy * wt.a + dx * wt.c + wt.tx; - wt.ty = dy * wt.b + dx * wt.d + wt.ty; - - var temp = wt.a; - wt.a = -wt.c; - wt.c = temp; - - temp = wt.b; - wt.b = -wt.d; - wt.d = temp; - + if(texture.rotate) { + wt.copy(canvasRenderWorldTransform); + wt = canvasRenderWorldTransform; + GroupD8.appendRotationInv(wt, texture.rotate, dx, dy); // the anchor has already been applied above, so lets set it to zero dx = 0; dy = 0; - } - else - { - width = texture.crop.width; - height = texture.crop.height; - - dx = (texture.trim) ? texture.trim.x - this.anchor.x * texture.trim.width : this.anchor.x * -texture._frame.width; - dy = (texture.trim) ? texture.trim.y - this.anchor.y * texture.trim.height : this.anchor.y * -texture._frame.height; - } - - - + dx -= width/2; + dy -= height/2; // Allow for pixel rounding if (renderer.roundPixels) { diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index e43e8b5..41f5313 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -23,7 +23,7 @@ * @param [frame] {PIXI.Rectangle} The rectangle frame of the texture to show * @param [crop] {PIXI.Rectangle} The area of original texture * @param [trim] {PIXI.Rectangle} Trimmed texture rectangle - * @param [rotate] {boolean} indicates whether the texture should be rotated by 90 degrees ( used by texture packer ) + * @param [rotate] {number} indicates how the texture was rotated by texture packer. See {@link PIXI.GroupD8} */ function Texture(baseTexture, frame, crop, trim, rotate) { @@ -113,13 +113,14 @@ */ this.crop = crop || frame;//new math.Rectangle(0, 0, 1, 1); - /** - * Indicates whether the texture should be rotated by 90 degrees - * - * @private - * @member {boolean} - */ - this.rotate = !!rotate; + this._rotate = +(rotate || 0); + + if (rotate === true) { + // this is old texturepacker legacy, some games/libraries are passing "true" or 1 for rotated textures + this._rotate = 2; + } else if (this.rotate % 2 !== 0) { + throw 'Texture rotation must be divisible by 2'; + } if (baseTexture.hasLoaded) { @@ -196,6 +197,29 @@ this._updateUvs(); } } + }, + /** + * Indicates whether the texture is rotated inside the atlas + * set to 2 to compensate for texture packer rotation + * set to 6 to compensate for spine packer rotation + * can be used to rotate or mirror sprites + * See {@link PIXI.GroupD8} for explanation + * + * @member {number} + */ + rotate: { + get: function () + { + return this._rotate; + }, + set: function (rotate) + { + this._rotate = rotate; + if (this.valid) + { + this._updateUvs(); + } + } } }); diff --git a/src/core/textures/TextureUvs.js b/src/core/textures/TextureUvs.js index b3a5f7f..6bf607e 100644 --- a/src/core/textures/TextureUvs.js +++ b/src/core/textures/TextureUvs.js @@ -23,11 +23,13 @@ module.exports = TextureUvs; +var GroupD8 = require('../math/GroupD8'); + /** * Sets the texture Uvs based on the given frame information * @param frame {PIXI.Rectangle} * @param baseFrame {PIXI.Rectangle} - * @param rotate {boolean} Whether or not the frame is rotated + * @param rotate {int} Rotation of frame, see {@link PIXI.GroupD8} * @private */ TextureUvs.prototype.set = function (frame, baseFrame, rotate) @@ -37,17 +39,25 @@ if(rotate) { - this.x0 = (frame.x + frame.height) / tw; - this.y0 = frame.y / th; - - this.x1 = (frame.x + frame.height) / tw; - this.y1 = (frame.y + frame.width) / th; - - this.x2 = frame.x / tw; - this.y2 = (frame.y + frame.width) / th; - - this.x3 = frame.x / tw; - this.y3 = frame.y / th; + //width and height div 2 div baseFrame size + var swapWidthHeight = GroupD8.isSwapWidthHeight(rotate); + var w2 = (swapWidthHeight ? frame.height : frame.width) / 2 / tw; + var h2 = (swapWidthHeight ? frame.width : frame.height) / 2 / th; + //coordinates of center + var cX = frame.x / tw + w2; + var cY = frame.y / th + h2; + rotate = GroupD8.add(rotate, GroupD8.NW); //NW is top-left corner + this.x0 = cX + w2 * GroupD8.uX(rotate); + this.y0 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); //rotate 90 degrees clockwise + this.x1 = cX + w2 * GroupD8.uX(rotate); + this.y1 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); + this.x2 = cX + w2 * GroupD8.uX(rotate); + this.y2 = cY + h2 * GroupD8.uY(rotate); + rotate = GroupD8.add(rotate, 2); + this.x3 = cX + w2 * GroupD8.uX(rotate); + this.y3 = cY + h2 * GroupD8.uY(rotate); } else { diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index f30032c..3737329 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -68,7 +68,7 @@ size.width /= resolution; size.height /= resolution; - resource.textures[i] = new core.Texture(res.texture.baseTexture, size, size.clone(), trim, frames[i].rotated); + resource.textures[i] = new core.Texture(res.texture.baseTexture, size, size.clone(), trim, frames[i].rotated ? 2 : 0); // lets also add the frame to pixi's global cache for fromFrame and fromImage functions core.utils.TextureCache[i] = resource.textures[i];