Skip to content

Commit a9bf339

Browse files
committed
Fully working sci-fly demo using a single gl draw to blit all of the tiles at once. Theoretically extremely fast (requires testing). Works here in FireFox and Chrome at 60 fps on an i7 4770 with Nvidia 780 GTX drawing typically 1989 tiles per frame.
1 parent 1b7eaad commit a9bf339

2 files changed

Lines changed: 46 additions & 59 deletions

File tree

src/pixi/extras/Tilemap.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -235,86 +235,95 @@ PIXI.Tilemap.prototype._renderVisibleLayer = function( _layer, renderSession )
235235
{
236236
var gl = renderSession.gl;
237237
var shader = renderSession.shaderManager.tilemapShader;
238-
// this.shaders.setProgram(this.shaders.blitShaderProgram, _textureNumber);
239238

239+
// calculate visible tile extents
240240
var firstX = Math.max(Math.floor(this.scrollX / this.tileWide), 0);
241241
var lastX = Math.min(firstX + Math.ceil(this.game.width / this.tileWide) + 1, this.mapWide);
242242
var firstY = Math.max(Math.floor(this.scrollY / this.tileHigh), 0);
243243
var lastY = Math.min(firstY + Math.ceil(this.game.height / this.tileHigh) + 1, this.mapHigh);
244-
var len = (lastX - firstX) * (lastY - firstY);
245244

245+
// TODO: switch to game.width or PIXI equivalent
246246
var screenWide2 = gl.drawingBufferWidth * 0.5;
247247
var screenHigh2 = gl.drawingBufferHeight * 0.5;
248248

249249
// calculate inverse to avoid division in loop
250250
var iWide = 1.0 / screenWide2;
251251
var iHigh = 1.0 / screenHigh2;
252252

253-
var scale = 1.0;
254-
var wide = this.tileWide * scale * 0.5 / screenWide2;
255-
var high = this.tileHigh * scale * 0.5 / screenHigh2;
253+
// scale tile dimensions for drawing surface size (this shader doesn't do any conversion)
254+
var wide = this.tileWide * 0.5 / screenWide2;
255+
var high = this.tileHigh * 0.5 / screenHigh2;
256256

257-
var old_t;
258-
var old_r;
259-
260-
var c = 0;
261257
var buffer = this.buffer;
258+
var oldT, oldR;
259+
var c = 0;
260+
261+
// for all tiles in the visible screen area
262262
for(var ty = firstY; ty < lastY; ty++)
263263
{
264+
// local row pointer to speed up x access
264265
var layerRow = _layer.data[ty];
265-
var sy = ty * this.tileHigh;
266+
267+
// calculate screen position of centre of this tile (in pixels)
268+
var sy = ty * this.tileHigh + this.tileHigh * 0.5;
266269

267270
for(var tx = firstX; tx < lastX; tx++)
268271
{
272+
// get the tile index from the map
269273
var tile = layerRow[tx].index - 1;
270274

275+
// if it's not an empty tile...
271276
if ( tile >= 0 )
272277
{
273-
var sx = tx * this.tileWide;
278+
var sx = tx * this.tileWide + this.tileWide * 0.5;
274279

280+
// calculate the source position of this tile index (in whole tiles)
275281
var tmx = tile % this.texTilesWide;
276282
var tmy = Math.floor(tile / this.texTilesWide);
277283

278-
// from blitSimpleDrawAnimImages
284+
// calculate the uv values for each corner of the tile in the source
279285
var uvl = tmx * this.scalex;
280286
var uvr = uvl + this.scalex;
281287
var uvt = tmy * this.scaley;
282288
var uvb = uvt + this.scaley;
283289

284-
//this._renderTile(gl, shader, bi, x * this.tileWide, y * this.tileHigh, tile);
285-
290+
// calculate the destination location of the tile in screen units (-1..1)
286291
var x = sx * iWide - 1;
287292
var y = 1 - sy * iHigh;
293+
294+
// calculate the bottom-left corner of the tile in screen units
288295
var l = x - wide;
289296
var b = y + high;
290297

298+
// for every tile except the first one...
291299
if ( c > 0 )
292300
{
293-
// degenerate triangle: repeat the last vertex
294-
buffer[ c ] = old_r;
295-
buffer[ c + 1 ] = old_t;
296-
// repeat the next vertex
301+
// add a degenerate triangle: repeat the last vertex
302+
buffer[ c ] = oldR;
303+
buffer[ c + 1 ] = oldT;
304+
// then repeat the next vertex
297305
buffer[ c + 4 ] = l;
298306
buffer[ c + 5 ] = b;
299-
// texture coordinates
307+
// pad with texture coordinates (probably not needed)
300308
buffer[ c + 2 ] = buffer[ c + 6 ] = uvl;
301309
buffer[ c + 3 ] = buffer[ c + 7 ] = uvt;
302310

311+
// advance the buffer index
303312
c += 8;
304313
}
305314

306-
// screen destination position
315+
// screen destination into the VBO
307316
// l, b, 0,1
308317
// l, t, 4,5
309318
// r, b, 8,9
310319
// r, t, 12,13
311320

312321
buffer[ c ] = buffer[ c + 4 ] = l;
313322
buffer[ c + 1 ] = buffer[ c + 9 ] = b;
314-
buffer[ c + 8 ] = buffer[ c + 12] = old_r = x + wide;
315-
buffer[ c + 5 ] = buffer[ c + 13] = old_t = y - high;
323+
buffer[ c + 8 ] = buffer[ c + 12] = oldR = x + wide;
324+
buffer[ c + 5 ] = buffer[ c + 13] = oldT = y - high;
316325

317-
// texture source position
326+
// texture source position into the VBO
318327
// l, b, 2,3
319328
// l, t, 6,7
320329
// r, b, 10,11
@@ -324,14 +333,23 @@ PIXI.Tilemap.prototype._renderVisibleLayer = function( _layer, renderSession )
324333
buffer[ c + 10] = buffer[ c + 14] = uvr; // r
325334
buffer[ c + 7 ] = buffer[ c + 15] = uvb; // b
326335

336+
// advance the buffer index
327337
c += 16;
328338
}
329339
}
330340
}
331341

342+
// set the scroll offset (in screen units)
343+
gl.uniform2f( shader.uScrollOffset, this.scrollX * iWide, -this.scrollY * iHigh );
344+
345+
// upload the VBO
332346
gl.bufferData( gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW );
347+
348+
// prepare the shader attributes
333349
gl.vertexAttribPointer( shader.aPosition, 4, gl.FLOAT, false, 0, 0 );
334-
gl.drawArrays(gl.TRIANGLE_STRIP, 0, len * 6 - 2);
350+
351+
// draw the entire VBO in one call
352+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, (lastX - firstX) * (lastY - firstY) * 6 - 2); // 4 + 2 (vertices + degenerates)
335353
};
336354

337355

src/pixi/renderers/webgl/shaders/TilemapShader.js

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,46 +40,16 @@ PIXI.TilemapShader = function(gl)
4040

4141
this.vertexSrc = [
4242
" precision lowp float;",
43+
" uniform vec2 uScrollOffset;",
4344
" attribute vec4 aPosition;",
4445
" varying vec2 vTexCoord;",
4546
" void main(void) {",
4647
" gl_Position.zw = vec2(1, 1);",
47-
" gl_Position.xy = aPosition.xy;",
48+
" gl_Position.xy = aPosition.xy - uScrollOffset;",
4849
" vTexCoord = aPosition.zw;",
4950
" }"
5051
];
5152

52-
/**
53-
* The fragment shader.
54-
* @property fragmentSrc
55-
* @type Array
56-
this.fragmentSrc = [
57-
" precision mediump float;",
58-
" uniform sampler2D uImageSampler;",
59-
" varying vec2 vTexCoord;",
60-
" void main(void) {",
61-
" gl_FragColor = texture2D(uImageSampler, vTexCoord);",
62-
" }"
63-
];
64-
*/
65-
66-
/**
67-
* The vertex shader.
68-
* @property vertexSrc
69-
* @type Array
70-
this.vertexSrc = [
71-
" uniform vec2 uScreenPosition;",
72-
" attribute vec4 aPosition;",
73-
" uniform mat3 uProjectionMatrix;",
74-
" varying vec2 vTexCoord;",
75-
" void main(void) {",
76-
" vec3 pos = uProjectionMatrix * (vec3(aPosition.xy, 1) + vec3(uScreenPosition, 0));",
77-
" gl_Position = vec4(pos.xy, 1, 1);",
78-
" vTexCoord = aPosition.zw;",
79-
" }"
80-
];
81-
*/
82-
8353
/**
8454
* A local texture counter for multi-texture shaders.
8555
* @property textureCount
@@ -107,12 +77,11 @@ PIXI.TilemapShader.prototype.init = function()
10777

10878
// get and store the attributes
10979
this.aPosition = gl.getAttribLocation(program, 'aPosition');
110-
// this.uProjectionMatrix = gl.getUniformLocation(program, 'uProjectionMatrix');
111-
// this.uScreenPosition = gl.getUniformLocation(program, 'uScreenPosition');
11280
this.uSampler = gl.getUniformLocation(program, 'uImageSampler');
81+
this.uScrollOffset = gl.getUniformLocation(program, 'uScrollOffset');
11382

114-
// this.attributes = [this.aScreenPosition, this.aPosition, this.uProjectionMatrix, this.uSampler];
11583
this.attributes = [this.aPosition, this.uSampler];
84+
this.uniforms = [this.uScrollOffset];
11685

11786
this.program = program;
11887
};

0 commit comments

Comments
 (0)