Skip to content

Commit 2177796

Browse files
committed
Added tileScaleX and tileScaleY support for Tile Sprites
1 parent 8c31209 commit 2177796

6 files changed

Lines changed: 144 additions & 102 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ There is a third game config property called `pixelArt`. If set to `true` it's t
5252
* `ScenePlugin.sleep` (and the corresponding methods in Scene Systems and the Scene Manager) now has a new optional `data` argument, which is passed to the target Scene and emitted in its 'sleep' event.
5353
* `ScenePlugin.wake` (and the corresponding methods in Scene Systems and the Scene Manager) now has a new optional `data` argument, which is passed to the target Scene and emitted in its 'wake' event.
5454
* `ScenePlugin.setActive` now has a new optional `data` argument, which is passed to the target Scene and emitted in its 'pause' or 'resume' events.
55+
* `TileSprite.tileScaleX` and `tileScaleY` are two new properties that allow you to control the scale of the texture within the Tile Sprite. This impacts the way the repeating texture is scaled, and is independent to scaling the Tile Sprite itself. It works in both Canvas and WebGL mode.
5556

5657
### Updates
5758

@@ -62,6 +63,7 @@ There is a third game config property called `pixelArt`. If set to `true` it's t
6263
* If the Blitter object has no Bob's to render it will now abort immediately, avoiding several context calls in Canvas mode.
6364
* `Scene.run` will now pass the optional `data` object in all cases, no matter if it's waking, resuming or starting a Scene (thanks @rook2pawn)
6465
* `ScenePlugin.start` and `ScenePlugin.restart` will now always queue the op with the Scene Manager, regardless of the state of the Scene, in order to avoid issues where plugins carry on running for a frame before closing down. Fix #3776 (thanks @jjalonso)
66+
* The `batchTileSprite` method has been removed from the `TextureTintPipeline` class, because it is now handled internally bu the Tile Sprite object itself.
6567

6668
### Bug Fixes
6769

src/gameobjects/tilesprite/TileSprite.js

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,21 @@ var TileSpriteRender = require('./TileSpriteRender');
1919
* The texture can be scrolled and scaled independently of the TileSprite itself. Textures will automatically wrap and
2020
* are designed so that you can create game backdrops using seamless textures as a source.
2121
*
22-
* [description]
22+
* You shouldn't ever create a TileSprite any larger than your actual screen size. If you want to create a large repeating background
23+
* that scrolls across the whole map of your game, then you create a TileSprite that fits the screen size and then use the `tilePosition`
24+
* property to scroll the texture as the player moves. If you create a TileSprite that is thousands of pixels in size then it will
25+
* consume huge amounts of memory and cause performance issues. Remember: use `tilePosition` to scroll your texture and `tileScale` to
26+
* adjust the scale of the texture - don't resize the sprite itself or make it larger than it needs.
27+
*
28+
* An important note about Tile Sprites and NPOT textures: Internally, TileSprite textures use GL_REPEAT to provide
29+
* seamless repeating of the textures. This, combined with the way in which the textures are handled in WebGL, means
30+
* they need to be POT (power-of-two) sizes in order to wrap. If you provide a NPOT (non power-of-two) texture to a
31+
* TileSprite it will generate a POT sized canvas and draw your texture to it, scaled up to the POT size. It's then
32+
* scaled back down again during rendering to the original dimensions. While this works, in that it allows you to use
33+
* any size texture for a Tile Sprite, it does mean that NPOT textures are going to appear anti-aliased when rendered,
34+
* due to the interpolation that took place when it was resized into a POT texture. This is especially visible in
35+
* pixel art graphics. If you notice it and it becomes an issue, the only way to avoid it is to ensure that you
36+
* provide POT textures for Tile Sprites.
2337
*
2438
* @class TileSprite
2539
* @extends Phaser.GameObjects.GameObject
@@ -102,6 +116,26 @@ var TileSprite = new Class({
102116
*/
103117
this.tilePositionY = 0;
104118

119+
/**
120+
* The horizontal scale of the Tile Sprite texture.
121+
*
122+
* @name Phaser.GameObjects.TileSprite#tileScaleX
123+
* @type {number}
124+
* @default 1
125+
* @since 3.11.0
126+
*/
127+
this.tileScaleX = 1;
128+
129+
/**
130+
* The vertical scale of the Tile Sprite texture.
131+
*
132+
* @name Phaser.GameObjects.TileSprite#tileScaleY
133+
* @type {number}
134+
* @default 1
135+
* @since 3.11.0
136+
*/
137+
this.tileScaleY = 1;
138+
105139
/**
106140
* Whether the Tile Sprite has changed in some way, requiring an re-render of its tile texture.
107141
*
@@ -116,9 +150,10 @@ var TileSprite = new Class({
116150

117151
/**
118152
* The texture that the Tile Sprite is rendered to, which is then rendered to a Scene.
153+
* In WebGL this is a WebGLTexture. In Canvas it's a Canvas Fill Pattern.
119154
*
120155
* @name Phaser.GameObjects.TileSprite#tileTexture
121-
* @type {?WebGLTexture}
156+
* @type {?(WebGLTexture|CanvasPattern)}
122157
* @default null
123158
* @since 3.0.0
124159
*/
@@ -165,7 +200,7 @@ var TileSprite = new Class({
165200
* @default null
166201
* @since 3.0.0
167202
*/
168-
this.canvasPattern = null;
203+
// this.canvasPattern = null;
169204

170205
/**
171206
* The Canvas that the TileSprite's texture is rendered to.
@@ -185,6 +220,14 @@ var TileSprite = new Class({
185220
*/
186221
this.canvasBufferCtx = this.canvasBuffer.getContext('2d');
187222

223+
/**
224+
* The previous Texture Frame being used.
225+
*
226+
* @name Phaser.GameObjects.Components.Texture#oldFrame
227+
* @type {Phaser.Textures.Frame}
228+
* @private
229+
* @since 3.0.0
230+
*/
188231
this.oldFrame = null;
189232

190233
this.updateTileTexture();
@@ -236,42 +279,42 @@ var TileSprite = new Class({
236279
*/
237280
updateTileTexture: function ()
238281
{
239-
if (!this.dirty && this.oldFrame === this.frame)
282+
var frame = this.frame;
283+
284+
if (!this.dirty && this.oldFrame === frame)
240285
{
241286
return;
242287
}
243288

244-
this.oldFrame = this.frame;
289+
this.oldFrame = frame;
245290

246-
this.canvasBufferCtx.clearRect(0, 0, this.canvasBuffer.width, this.canvasBuffer.height);
291+
var ctx = this.canvasBufferCtx;
292+
var canvas = this.canvasBuffer;
247293

248-
if (this.renderer.gl)
249-
{
250-
this.canvasBufferCtx.drawImage(
251-
this.frame.source.image,
252-
this.frame.cutX, this.frame.cutY,
253-
this.frame.cutWidth, this.frame.cutHeight,
254-
0, 0,
255-
this.potWidth, this.potHeight
256-
);
257-
258-
this.tileTexture = this.renderer.canvasToTexture(this.canvasBuffer, this.tileTexture);
259-
}
260-
else
294+
var fw = this.potWidth;
295+
var fh = this.potHeight;
296+
297+
if (!this.renderer.gl)
261298
{
262-
this.canvasBuffer.width = this.frame.cutWidth;
263-
this.canvasBuffer.height = this.frame.cutHeight;
264-
this.canvasBufferCtx.drawImage(
265-
this.frame.source.image,
266-
this.frame.cutX, this.frame.cutY,
267-
this.frame.cutWidth, this.frame.cutHeight,
268-
0, 0,
269-
this.frame.cutWidth, this.frame.cutHeight
270-
);
271-
272-
this.canvasPattern = this.canvasBufferCtx.createPattern(this.canvasBuffer, 'repeat');
299+
fw = frame.cutWidth;
300+
fh = frame.cutHeight;
273301
}
274302

303+
ctx.clearRect(0, 0, canvas.width, canvas.height);
304+
305+
canvas.width = fw;
306+
canvas.height = fh;
307+
308+
ctx.drawImage(
309+
frame.source.image,
310+
frame.cutX, frame.cutY,
311+
frame.cutWidth, frame.cutHeight,
312+
0, 0,
313+
fw, fh
314+
);
315+
316+
this.tileTexture = (this.renderer.gl) ? this.renderer.canvasToTexture(canvas, this.tileTexture) : ctx.createPattern(canvas, 'repeat');
317+
275318
this.dirty = false;
276319
},
277320

@@ -291,7 +334,7 @@ var TileSprite = new Class({
291334

292335
CanvasPool.remove(this.canvasBuffer);
293336

294-
this.canvasPattern = null;
337+
this.tileTexture = null;
295338
this.canvasBufferCtx = null;
296339
this.canvasBuffer = null;
297340

src/gameobjects/tilesprite/TileSpriteCanvasRenderer.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ var TileSpriteCanvasRenderer = function (renderer, src, interpolationPercentage,
9999
if (parentMatrix !== undefined)
100100
{
101101
var matrix = parentMatrix.matrix;
102+
102103
ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
103104
}
104105

@@ -116,9 +117,12 @@ var TileSpriteCanvasRenderer = function (renderer, src, interpolationPercentage,
116117
ctx.translate(-(src.originX * src.width), -(src.originY * src.height));
117118

118119
// Draw
120+
121+
ctx.scale(src.tileScaleX, src.tileScaleY);
122+
119123
ctx.translate(-this.tilePositionX, -this.tilePositionY);
120-
ctx.fillStyle = src.canvasPattern;
121-
ctx.fillRect(this.tilePositionX, this.tilePositionY, src.width, src.height);
124+
ctx.fillStyle = src.tileTexture;
125+
ctx.fillRect(this.tilePositionX, this.tilePositionY, src.width / src.tileScaleX, src.height / src.tileScaleY);
122126

123127
ctx.restore();
124128
};

src/gameobjects/tilesprite/TileSpriteWebGLRenderer.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
var GameObject = require('../GameObject');
8+
var Utils = require('../../renderer/webgl/Utils');
89

910
/**
1011
* Renders this Game Object with the WebGL Renderer to the given Camera.
@@ -30,7 +31,29 @@ var TileSpriteWebGLRenderer = function (renderer, src, interpolationPercentage,
3031

3132
src.updateTileTexture();
3233

33-
this.pipeline.batchTileSprite(this, camera, parentMatrix);
34+
var getTint = Utils.getTintAppendFloatAlpha;
35+
36+
this.pipeline.batchTexture(
37+
src,
38+
src.tileTexture,
39+
src.frame.width * src.tileScaleX, src.frame.height * src.tileScaleY,
40+
src.x, src.y,
41+
src.width, src.height,
42+
src.scaleX, src.scaleY,
43+
src.rotation,
44+
src.flipX, src.flipY,
45+
src.scrollFactorX, src.scrollFactorY,
46+
src.originX * src.width, src.originY * src.height,
47+
0, 0, src.width, src.height,
48+
getTint(src._tintTL, camera.alpha * src._alphaTL),
49+
getTint(src._tintTR, camera.alpha * src._alphaTR),
50+
getTint(src._tintBL, camera.alpha * src._alphaBL),
51+
getTint(src._tintBR, camera.alpha * src._alphaBR),
52+
(src.tilePositionX % src.frame.width) / src.frame.width,
53+
(src.tilePositionY % src.frame.height) / src.frame.height,
54+
camera,
55+
parentMatrix
56+
);
3457
};
3558

3659
module.exports = TileSpriteWebGLRenderer;

src/renderer/webgl/WebGLRenderer.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,14 +1120,10 @@ var WebGLRenderer = new Class({
11201120
wrap = gl.REPEAT;
11211121
}
11221122

1123-
if (scaleMode === CONST.ScaleModes.LINEAR)
1123+
if (scaleMode === CONST.ScaleModes.LINEAR && this.config.antialias)
11241124
{
11251125
filter = gl.LINEAR;
11261126
}
1127-
else if (scaleMode === CONST.ScaleModes.NEAREST || !this.config.antialias)
1128-
{
1129-
filter = gl.NEAREST;
1130-
}
11311127

11321128
if (!source && typeof width === 'number' && typeof height === 'number')
11331129
{
@@ -1157,7 +1153,7 @@ var WebGLRenderer = new Class({
11571153
* @param {object} pixels - pixel data
11581154
* @param {integer} width - Width of the texture in pixels
11591155
* @param {integer} height - Height of the texture in pixels
1160-
* @param {boolean} pma - Does the texture hace premultiplied alpha.
1156+
* @param {boolean} pma - Does the texture have premultiplied alpha?
11611157
*
11621158
* @return {WebGLTexture} Raw WebGLTexture
11631159
*/

0 commit comments

Comments
 (0)