Advanced Rendering: Tiles

Import the device module and ui.View class

import device as device;
import ui.View as View;

Class: Application

exports = Class(GC.Application, function () {

	this.initUI = function() {
		var Canvas = device.get("Canvas");

		var sizeX = 20;
		var sizeY = 20;

		this._cnt = 0;
		this._canvasTiles = new Canvas({width: 40 * sizeX, height: 40 * sizeY});
		this._contextTiles = this._canvasTiles.getContext('2d');
		for (b = 0; b < 40; b++) {
			for (a = 0; a < 40; a++) {
				var c1 = (~~(64 + (a / 40 * 191))).toString(16)
				var c2 = (~~(64 + (b / 40 * 191))).toString(16)
				if (c1.length < 2) { c1 = '0' + c1; }
				if (c2.length < 2) { c2 = '0' + c2; }

				this._contextTiles.fillStyle = '#' + c1 + '00' + c2;
				this._contextTiles.fillRect(a * sizeX, b * sizeY, sizeX, sizeY);

				this._contextTiles.fillStyle = '#000000';
				this._contextTiles.fillText(b * 40 + a, a * sizeX + 2, b * sizeY + 10)
			}
		}

Create a TileView instance

		this._tileView = new TileView({
			superview: this.view,
			width: device.width,
			height: device.height,
			sizeX: 48,
			sizeY: 48,
			renderTileCB: bind(this, "_renderTile")
		});
		this._tileView.tick = bind(this, "tick");
	};

	this._renderTile = function(ctx, offsetX, offsetY, x, y) {
		ctx.drawImage(this._canvasTiles, offsetX * 20, offsetY * 20, 20, 20, x, y, 48, 48);
	};

	this.tick = function(dt) {
		this._cnt += dt / 10;
		this._tileView.scrollHorizontal(~~(Math.sin(this._cnt * 0.02) * 2));
		this._tileView.scrollVertical(~~(Math.sin(this._cnt * 0.025) * 3));
	};

	this.launchUI = function() {};
});

Class: TileView

var TileView = Class(View, function(supr) {
	this.init = function(opts) {
		supr(this, "init", [opts]);

		this._renderTileCB = opts.renderTileCB;

		this._offsetX = 0;
		this._offsetY = 0;
		this._tileX = 0;
		this._tileY = 0;
		this._sX = 0;
		this._sY = 0;
		this._width = device.width;
		this._height = device.height;
		this._mTX = opts.sizeX;
		this._mTY = opts.sizeY;
		this._tX1 = Math.ceil(this._width  / this._mTX);
		this._tY1 = Math.ceil(this._height / this._mTY);
		this._tX2 = this._tX1 + 1;
		this._tY2 = this._tY1 + 1;
		this._bufferSizeX = this._tX2 * this._mTX;
		this._bufferSizeY = this._tY2 * this._mTY;

		var Canvas = device.get("Canvas");
		this._canvasBuffer = new Canvas({width: this._bufferSizeX, height: this._bufferSizeY});
		this._contextBuffer = this._canvasBuffer.getContext('2d');

		this._renderTilesToBuffer(0, 0, this._tX1, this._tY1, 0, 0);
	};

	this._renderTilesToBuffer = function(startX, startY, endX, endY, offsetX, offsetY) {
		var a, b;

		if ((offsetX < 0) || (offsetY < 0)) { return; }

		b = 0;
		for (y = startY; y <= endY; y++) {
			a = 0;
			for (x = startX; x <= endX; x++) {
				this._renderTileCB(this._contextBuffer, a + offsetX, b + offsetY, x * this._mTX, y * this._mTY);
				a++;
			}
			b++;
		}
	};

	this._copyBuffer = function(ctx, sx, sy, sw, sh, dx, dy) {
		if ((sw <= 0) || (sh <= 0)) { return; }
		ctx.drawImage(this._canvasBuffer, sx, sy, sw, sh, dx, dy, sw, sh);
	};

	this._copyScreen = function(ctx) {
		var sizeX = this._sX * this._mTX,
			sizeY = this._sY * this._mTY,
			sx = 0,
			sy = 0,
			sw = device.width,
			sh = device.height,
			dx = 0,
			dy = 0;

		if ((this._sX === 0) && (this._sY === 0)) {
			this._copyBuffer(ctx, this._offsetX, this._offsetY, sw, sh, dx, dy);
		} else if (this._sY === 0) {
			sx = this._offsetX + sizeX;
			sy = this._offsetY;
			sw = this._bufferSizeX - this._offsetX - sizeX;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);

			sx = 0;
			sy = this._offsetY;
			sw = sizeX + this._offsetX - this._mTX;

			dx = this._bufferSizeX - this._offsetX - sizeX;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);
		} else if (this._sX === 0) {
			sx = this._offsetX;
			sy = this._offsetY + sizeY;
			sh = this._bufferSizeY - this._offsetY - sizeY;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);

			sx = this._offsetX;
			sy = 0;
			sh = sizeY + this._offsetY - this._mTY;

			dy = this._bufferSizeY - this._offsetY - sizeY;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);
		} else {

Copy right bottom to left top…

			sx = this._offsetX + sizeX;
			sy = this._offsetY + sizeY;
			sw = this._bufferSizeX - this._offsetX - sizeX;
			sh = this._bufferSizeY - this._offsetY - sizeY;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);

Copy left top to right bottom…

			sx = 0;
			sy = 0;
			sw = this._offsetX + sizeX - this._mTX;
			sh = this._offsetY + sizeY - this._mTY;

			dx = this._bufferSizeX - this._offsetX - sizeX;
			dy = this._bufferSizeY - this._offsetY - sizeY;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);

Copy right top to left bottom…

			sx = this._offsetX + sizeX;
			sy = 0;
			sw = this._bufferSizeX - this._offsetX - sizeX;
			sh = this._offsetY + sizeY - this._mTY;

			dx = 0;
			dy = this._bufferSizeY - this._offsetY - sizeY;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);

Copy right top to left bottom…

			sx = 0;
			sy = this._offsetY + sizeY;
			sw = this._offsetX + sizeX - this._mTX;
			sh = this._bufferSizeY - this._offsetY - sizeY;

			dx = this._bufferSizeX - this._offsetX - sizeX;
			dy = 0;

			this._copyBuffer(ctx, sx, sy, sw, sh, dx, dy);
		}
	};

	this.scrollVertical = function(value) {
		this._offsetY += value;
		while (this._offsetY < 0) {
			if (this._tileY > 0) {
				this._offsetY += this._mTY;
				this._sY--;
				this._tileY--;
				if (this._sY < 0) { this._sY += this._tY2; }
			} else {
				this._offsetY = 0;
				break;
			}

			this._renderTilesToBuffer(0, this._sY, this._sX, this._sY, this._tileX + this._tX2 - this._sX, this._tileY);
			this._renderTilesToBuffer(this._sX, this._sY, this._tX1, this._sY, this._tileX, this._tileY);
		}

		while (this._offsetY >= this._mTY) {
			this._renderTilesToBuffer(0, this._sY, this._sX, this._sY, this._tileX + this._tX2 - this._sX, this._tY2 + this._tileY);
			this._renderTilesToBuffer(this._sX, this._sY, this._tX1, this._sY, this._tileX, this._tY2 + this._tileY);

			this._offsetY -= this._mTY;
			this._sY++;
			this._tileY++;
			if (this._sY >= this._tY2) { this._sY -= this._tY2; }
		}
	};

	this.scrollHorizontal = function(value) {
		this._offsetX += value;
		while (this._offsetX < 0) {
			if (this._tileX > 0) {
				this._offsetX += this._mTX;
				this._sX--;
				this._tileX--;
				if (this._sX < 0) { this._sX += this._tX2; }
			} else {
				this._offsetX = 0;
				break;
			}

			this._renderTilesToBuffer(this._sX, 0, this._sX, this._tY1, this._tileX, this._tileY + this._tY2 - this._sY);
			this._renderTilesToBuffer(this._sX, this._sY, this._sX, this._tY1, this._tileX, this._tileY);
		}

		while (this._offsetX >= this._mTX) {
			this._renderTilesToBuffer(this._sX, 0, this._sX, this._sY, this._tX2 + this._tileX, this._tileY + this._tY2 - this._sY);
			this._renderTilesToBuffer(this._sX, this._sY, this._sX, this._tY1, this._tX2 + this._tileX, this._tileY);

			this._offsetX -= this._mTX;
			this._sX++;
			this._tileX++;
			if (this._sX >= this._tX2) { this._sX -= this._tX2; }
		}
	};

	this.render = function(ctx) {
		this._copyScreen(ctx);
	};

	this.launchUI = function () {};
});