Skip to content
Browse files

Refactor canvas pool and render functions

This re-enables plant rendering.
  • Loading branch information...
1 parent 08a0550 commit fc698804c319f675aa6bffe59c1b2cfee7df3738 Blixt committed Mar 1, 2014
Showing with 114 additions and 60 deletions.
  1. +72 −23 lib/regionrenderer.js
  2. +42 −37 lib/worldrenderer.js
View
95 lib/regionrenderer.js
@@ -46,41 +46,86 @@ RegionRenderer.STATE_LOADING = 1;
RegionRenderer.STATE_READY = 2;
// TODO: Implement support for rendering only a part of the region.
-RegionRenderer.prototype.render = function (renderer) {
+RegionRenderer.prototype.render = function (renderer, offsetX, offsetY) {
if (this.state != RegionRenderer.STATE_READY) return;
- this._renderEntities(renderer);
- this._renderTiles(renderer);
+ this._renderEntities(renderer, offsetX, offsetY);
+ this._renderTiles(renderer, offsetX, offsetY);
};
-RegionRenderer.prototype._renderEntities = function (renderer) {
+RegionRenderer.prototype._renderEntities = function (renderer, offsetX, offsetY) {
+ var minX = 0, maxX = 0, minY = 0, maxY = 0,
+ originX = this.x * TILES_X, originY = this.y * TILES_Y,
+ allSprites = [];
+
for (var i = 0; i < this.entities.length; i++) {
- var entity = this.entities[i];
+ var entity = this.entities[i],
+ sprites = null;
+
switch (entity.__name__ + entity.__version__) {
case 'ItemDropEntity1':
- this._renderItem(renderer, entity);
+ sprites = this._renderItem(renderer, entity);
break;
case 'MonsterEntity1':
- this._renderMonster(renderer, entity);
+ sprites = this._renderMonster(renderer, entity);
break;
case 'NpcEntity1':
// TODO: Convert to version 2 before rendering.
break;
case 'NpcEntity2':
- this._renderNPC(renderer, entity);
+ sprites = this._renderNPC(renderer, entity);
break;
case 'ObjectEntity1':
// TODO: Convert to version 2 before rendering.
break;
case 'ObjectEntity2':
- this._renderObject(renderer, entity);
+ sprites = this._renderObject(renderer, entity);
break;
case 'PlantEntity1':
- this._renderPlant(renderer, entity);
+ sprites = this._renderPlant(renderer, entity);
break;
default:
console.warn('Unsupported entity/version:', entity);
}
+
+ if (sprites) {
+ for (var j = 0; j < sprites.length; j++) {
+ var sprite = sprites[j];
+ if (!sprite.image) continue;
+
+ if (!sprite.sx) sprite.sx = 0;
+ if (!sprite.sy) sprite.sy = 0;
+ if (!sprite.width) sprite.width = sprite.image.width;
+ if (!sprite.height) sprite.height = sprite.image.height;
+
+ sprite.canvasX = (sprite.x - originX) * TILE_WIDTH;
+ sprite.canvasY = REGION_HEIGHT - (sprite.y - originY) * TILE_HEIGHT - sprite.height;
+
+ minX = Math.min(sprite.canvasX, minX);
+ maxX = Math.max(sprite.canvasX + sprite.width, maxX);
+ minY = Math.min(sprite.canvasY, minY);
+ maxY = Math.max(sprite.canvasY + sprite.height, maxY);
+
+ allSprites.push(sprite);
+ }
+ }
+ }
+
+ var canvas = renderer.getCanvas(this, 2, maxX - minX, maxY - minY);
+ if (allSprites.length) {
+ canvas.style.left = (offsetX + minX * renderer.zoom) + 'px';
+ canvas.style.top = (offsetY + minY * renderer.zoom) + 'px';
+ canvas.style.visibility = 'visible';
+
+ var context = canvas.getContext('2d');
+
+ for (var i = 0; i < allSprites.length; i++) {
+ var sprite = allSprites[i];
+ context.drawImage(sprite.image, sprite.sx, sprite.sy, sprite.width, sprite.height,
+ -minX + sprite.canvasX, -minY + sprite.canvasY, sprite.width, sprite.height);
+ }
+ } else {
+ canvas.style.visibility = 'hidden';
}
};
@@ -109,21 +154,25 @@ RegionRenderer.prototype._renderObject = function (renderer, entity) {
RegionRenderer.prototype._renderPlant = function (renderer, entity) {
var assets = renderer.assets,
position = entity.tilePosition,
- x = position[0] - renderer.currentX,
- y = position[1] - renderer.currentY;
-
- for (var i = 0; i < entity.pieces.length; i++) {
- var piece = entity.pieces[i];
-
- var image = assets.getImage(piece.image);
- if (!image) { /* this.dirty = true; */ continue; }
-
- //context.drawImage(image, (x + piece.offset[0]) * 8, (32 - (y + piece.offset[1])) * 8 - image.height);
- }
+ x = position[0],
+ y = position[1];
+
+ return entity.pieces.map(function (piece) {
+ return {
+ image: assets.getImage(piece.image),
+ x: x + piece.offset[0],
+ y: y + piece.offset[1]
+ };
+ });
};
-RegionRenderer.prototype._renderTiles = function (renderer) {
- var canvas = renderer.getCanvas(this, 'tiles');
+RegionRenderer.prototype._renderTiles = function (renderer, offsetX, offsetY) {
+ var canvas = renderer.getCanvas(this, 1, REGION_WIDTH, REGION_HEIGHT);
+ canvas.style.left = offsetX + 'px';
+ canvas.style.top = offsetY + 'px';
+ canvas.style.visibility = 'visible';
+
+ if (!this.dirty) return;
// Prepare the rendering step.
var context = canvas.getContext('2d');
View
79 lib/worldrenderer.js
@@ -37,6 +37,11 @@ function WorldRenderer(viewport, worldManager, assetsManager) {
this.centerY = 0;
this.zoom = 1;
+ this.viewportX = 0;
+ this.viewportY = 0;
+ this.screenRegionWidth = REGION_WIDTH;
+ this.screenRegionHeight = REGION_HEIGHT;
+
this.materials = assetsManager.getResourceLoader('.material');
this.matmods = assetsManager.getResourceLoader('.matmod');
this.objects = assetsManager.getResourceLoader('.object');
@@ -59,8 +64,6 @@ function WorldRenderer(viewport, worldManager, assetsManager) {
this._fromRegionY = 0;
this._toRegionX = 0;
this._toRegionY = 0;
- this._originX = 0;
- this._originY = 0;
this._visibleRegionsX = 0;
this._visibleRegionsY = 0;
@@ -89,39 +92,49 @@ WorldRenderer.prototype.center = function (tileX, tileY) {
this._calculateViewport();
};
-WorldRenderer.prototype.getCanvas = function (region, id) {
- var key = region.x + ':' + region.y + ':' + id;
+WorldRenderer.prototype.getCanvas = function (region, z, width, height) {
+ var key = region.x + ':' + region.y + ':' + z;
- var item = this._poolLookup[key];
+ var item = this._poolLookup[key], canvas;
- if (!item) {
+ if (item) {
+ canvas = item.canvas;
+ } else {
if (this._freePool.length) {
item = this._freePool.pop();
+ canvas = item.canvas;
} else {
// Create new <canvas> elements as they are needed.
- var canvas = document.createElement('canvas');
- canvas.width = REGION_WIDTH;
- canvas.height = REGION_HEIGHT;
+ canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.visibility = 'hidden';
- canvas.style.width = this._screenRegionWidth + 'px';
- canvas.style.height = this._screenRegionHeight + 'px';
this.viewport.appendChild(canvas);
// Register the new canvas in the pool.
- item = {canvas: canvas, region: region, id: id};
+ item = {canvas: canvas, region: region, z: z};
this._canvasPool.push(item);
}
- item.id = id;
+ item.z = z;
item.region = region;
this._poolLookup[key] = item;
// Mark the region as dirty since it's not reusing a canvas.
region.dirty = true;
}
- return item.canvas;
+ // Only resize the canvas if necessary, since resizing clears the canvas.
+ if (canvas.width != width || canvas.height != height) {
+ canvas.width = width;
+ canvas.height = height;
+ region.dirty = true;
+ }
+
+ canvas.style.width = width * this.zoom + 'px';
+ canvas.style.height = height * this.zoom + 'px';
+ canvas.style.zIndex = z;
+
+ return canvas;
};
WorldRenderer.prototype.getRegion = function (regionX, regionY, opt_skipNeighbors) {
@@ -247,18 +260,10 @@ WorldRenderer.prototype.render = function () {
var region = this.getRegion(regionX, regionY);
if (!region) continue;
- // Position the canvas correctly.
- var canvas = this.getCanvas(region, 'tiles');
- var screenX = regionX * this._screenRegionWidth,
- screenY = (this._regionsY - regionY) * this._screenRegionHeight;
- canvas.style.left = (screenX - this._originX) + 'px';
- canvas.style.top = (screenY - this._originY) + 'px';
- canvas.style.visibility = (region.state == RegionRenderer.STATE_READY ? 'visible' : 'hidden');
-
- // Render to the canvas if necessary.
- if (region.dirty) {
- region.render(this);
- }
+ // Calculate the region's position in the viewport and render it.
+ var offsetX = regionX * this.screenRegionWidth - this.viewportX,
+ offsetY = (this._regionsY - regionY) * this.screenRegionHeight - this.viewportY;
+ region.render(this, offsetX, offsetY);
}
}
};
@@ -312,13 +317,13 @@ WorldRenderer.prototype.zoomOut = function () {
WorldRenderer.prototype._calculateRegions = function () {
if (!this._loaded) return;
- this._fromRegionX = Math.floor(this.centerX / TILES_X - this._bounds.width / 2 / this._screenRegionWidth);
- this._fromRegionY = Math.floor(this.centerY / TILES_Y - this._bounds.height / 2 / this._screenRegionHeight);
+ this._fromRegionX = Math.floor(this.centerX / TILES_X - this._bounds.width / 2 / this.screenRegionWidth);
+ this._fromRegionY = Math.floor(this.centerY / TILES_Y - this._bounds.height / 2 / this.screenRegionHeight);
this._toRegionX = this._fromRegionX + this._visibleRegionsX;
this._toRegionY = this._fromRegionY + this._visibleRegionsY;
- this._originX = this.centerX * this._screenTileWidth - this._bounds.width / 2,
- this._originY = ((this._regionsY + 1) * TILES_Y - this.centerY) * this._screenTileHeight - this._bounds.height / 2;
+ this.viewportX = this.centerX * this._screenTileWidth - this._bounds.width / 2,
+ this.viewportY = ((this._regionsY + 1) * TILES_Y - this.centerY) * this._screenTileHeight - this._bounds.height / 2;
this.requestRender();
};
@@ -328,20 +333,20 @@ WorldRenderer.prototype._calculateViewport = function () {
this._setup = true;
- this._screenRegionWidth = REGION_WIDTH * this.zoom;
- this._screenRegionHeight = REGION_HEIGHT * this.zoom;
+ this.screenRegionWidth = REGION_WIDTH * this.zoom;
+ this.screenRegionHeight = REGION_HEIGHT * this.zoom;
this._screenTileWidth = TILE_WIDTH * this.zoom;
this._screenTileHeight = TILE_HEIGHT * this.zoom;
this._bounds = this.viewport.getBoundingClientRect();
- this._visibleRegionsX = Math.ceil(this._bounds.width / this._screenRegionWidth + 1);
- this._visibleRegionsY = Math.ceil(this._bounds.height / this._screenRegionHeight + 1);
+ this._visibleRegionsX = Math.ceil(this._bounds.width / this.screenRegionWidth + 1);
+ this._visibleRegionsY = Math.ceil(this._bounds.height / this.screenRegionHeight + 1);
// Resize all the canvases to the correct size.
for (var i = 0; i < this._canvasPool.length; i++) {
var canvas = this._canvasPool[i].canvas;
- canvas.style.width = this._screenRegionWidth + 'px';
- canvas.style.height = this._screenRegionHeight + 'px';
+ canvas.style.width = (canvas.width * this.zoom) + 'px';
+ canvas.style.height = (canvas.height * this.zoom) + 'px';
}
this._calculateRegions();
@@ -379,7 +384,7 @@ WorldRenderer.prototype._prepareCanvasPool = function () {
region = poolItem.region;
if (region && this.isRegionVisible(region)) {
- poolLookup[region.x + ':' + region.y + ':' + poolItem.id] = poolItem;
+ poolLookup[region.x + ':' + region.y + ':' + poolItem.z] = poolItem;
} else {
poolItem.canvas.style.visibility = 'hidden';
freePool.push(poolItem);

0 comments on commit fc69880

Please sign in to comment.
Something went wrong with that request. Please try again.