diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js index cf713cf..aba6217 100644 --- a/src/mesh/NineSlicePlane.js +++ b/src/mesh/NineSlicePlane.js @@ -1,4 +1,5 @@ import Plane from './Plane'; +import CanvasTinter from '../core/sprites/canvas/CanvasTinter'; const DEFAULT_BORDER_SIZE = 10; @@ -103,6 +104,30 @@ */ this._bottomHeight = typeof bottomHeight !== 'undefined' ? bottomHeight : DEFAULT_BORDER_SIZE; + /** + * Cached tint value so we can tell when the tint is changed. + * + * @member {number} + * @protected + */ + this._cachedTint = 0xFFFFFF; + + /** + * Cached tinted texture. + * + * @member {HTMLCanvasElement} + * @protected + */ + this._tintedTexture = null; + + /** + * Temporary storage for canvas source coords + * + * @member {number[]} + * @private + */ + this._canvasUvs = null; + this.refresh(true); } @@ -147,13 +172,55 @@ _renderCanvas(renderer) { const context = renderer.context; + const transform = this.worldTransform; + const res = renderer.resolution; + const isTinted = this.tint !== 0xFFFFFF; + const texture = this._texture; + + // Work out tinting + if (isTinted) + { + if (this._cachedTint !== this.tint) + { + // Tint has changed, need to update the tinted texture and use that instead + + this._cachedTint = this.tint; + + this._tintedTexture = CanvasTinter.getTintedTexture(this, this.tint); + } + } + + const textureSource = !isTinted ? texture.baseTexture.source : this._tintedTexture; + + if (!this._canvasUvs) + { + this._canvasUvs = [0, 0, 0, 0, 0, 0, 0, 0]; + } + + const vertices = this.vertices; + const uvs = this._canvasUvs; + const u0 = isTinted ? 0 : texture.frame.x; + const v0 = isTinted ? 0 : texture.frame.y; + const u1 = u0 + texture.frame.width; + const v1 = v0 + texture.frame.height; + + uvs[0] = u0; + uvs[1] = u0 + this._leftWidth; + uvs[2] = u1 - this._rightWidth; + uvs[3] = u1; + uvs[4] = v0; + uvs[5] = v0 + this._topHeight; + uvs[6] = v1 - this._bottomHeight; + uvs[7] = v1; + + for (let i = 0; i < 8; i++) + { + uvs[i] *= texture.baseTexture.resolution; + } context.globalAlpha = this.worldAlpha; renderer.setBlendMode(this.blendMode); - const transform = this.worldTransform; - const res = renderer.resolution; - if (renderer.roundPixels) { context.setTransform( @@ -177,72 +244,20 @@ ); } - const base = this._texture.baseTexture; - const textureSource = base.source; - const w = base.width * base.resolution; - const h = base.height * base.resolution; - - this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11); - this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13); - this.drawSegment(context, textureSource, w, h, 4, 5, 14, 15); - this.drawSegment(context, textureSource, w, h, 8, 9, 18, 19); - this.drawSegment(context, textureSource, w, h, 10, 11, 20, 21); - this.drawSegment(context, textureSource, w, h, 12, 13, 22, 23); - this.drawSegment(context, textureSource, w, h, 16, 17, 26, 27); - this.drawSegment(context, textureSource, w, h, 18, 19, 28, 29); - this.drawSegment(context, textureSource, w, h, 20, 21, 30, 31); - } - - /** - * Renders one segment of the plane. - * to mimic the exact drawing behavior of stretching the image like WebGL does, we need to make sure - * that the source area is at least 1 pixel in size, otherwise nothing gets drawn when a slice size of 0 is used. - * - * @private - * @param {CanvasRenderingContext2D} context - The context to draw with. - * @param {CanvasImageSource} textureSource - The source to draw. - * @param {number} w - width of the texture - * @param {number} h - height of the texture - * @param {number} x1 - x index 1 - * @param {number} y1 - y index 1 - * @param {number} x2 - x index 2 - * @param {number} y2 - y index 2 - */ - drawSegment(context, textureSource, w, h, x1, y1, x2, y2) - { - // otherwise you get weird results when using slices of that are 0 wide or high. - const uvs = this.uvs; - const vertices = this.vertices; - - let sw = (uvs[x2] - uvs[x1]) * w; - let sh = (uvs[y2] - uvs[y1]) * h; - let dw = vertices[x2] - vertices[x1]; - let dh = vertices[y2] - vertices[y1]; - - // make sure the source is at least 1 pixel wide and high, otherwise nothing will be drawn. - if (sw < 1) + for (let row = 0; row < 3; row++) { - sw = 1; - } + for (let col = 0; col < 3; col++) + { + const ind = (col * 2) + (row * 8); + const sw = Math.max(1, uvs[col + 1] - uvs[col]); + const sh = Math.max(1, uvs[row + 5] - uvs[row + 4]); + const dw = Math.max(1, vertices[ind + 10] - vertices[ind]); + const dh = Math.max(1, vertices[ind + 11] - vertices[ind + 1]); - if (sh < 1) - { - sh = 1; + context.drawImage(textureSource, uvs[col], uvs[row + 4], sw, sh, + vertices[ind], vertices[ind + 1], dw, dh); + } } - - // make sure destination is at least 1 pixel wide and high, otherwise you get - // lines when rendering close to original size. - if (dw < 1) - { - dw = 1; - } - - if (dh < 1) - { - dh = 1; - } - - context.drawImage(textureSource, uvs[x1] * w, uvs[y1] * h, sw, sh, vertices[x1], vertices[y1], dw, dh); } /**