Skip to content

Commit

Permalink
world rendering basicly working
Browse files Browse the repository at this point in the history
  • Loading branch information
wartoshika committed Jul 25, 2017
1 parent 2d3551a commit a06cf1f
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 241 deletions.
2 changes: 1 addition & 1 deletion example/rpg/MyAwesomeRpgGame.ts
Expand Up @@ -67,7 +67,7 @@ class MyAwesomeRpgGame extends Client {

// create game objects
const camera = new OrthogonalCamera(1.5);
const world = new Level1('level1', 4);
const world = new Level1('level1');

// add global world things
world.addEntity(this.link);
Expand Down
2 changes: 1 addition & 1 deletion src/client/Game.ts
Expand Up @@ -45,7 +45,7 @@ export class Game extends Singleton {
this.currentWorld = world;

// render the world tile clusters
this.currentWorld.generateTileCluster();
this.currentWorld.generateWorld();

// set the world in the renderer
await this.renderer.setWorld(this.currentWorld);
Expand Down
1 change: 0 additions & 1 deletion src/client/render/Renderer.ts
Expand Up @@ -54,5 +54,4 @@ export interface Renderer {
*/
setCamera(camera: Camera): void;


}
2 changes: 1 addition & 1 deletion src/client/render/WorldRenderer.ts
Expand Up @@ -17,7 +17,7 @@ export interface WorldRenderer {
* renders all clusters into a cluster cache to speed
* up the drawing process if the renderer
*/
preRenderClusterTiles(): Promise<void>;
preRenderLayers(): Promise<void>;

/**
* renders the currently visible world
Expand Down
8 changes: 3 additions & 5 deletions src/client/render/canvas/CanvasRenderer.ts
Expand Up @@ -64,17 +64,15 @@ export class CanvasRenderer extends BasicRenderer {
this.gameDimension.x, this.gameDimension.y
)
);


}

/**
* pre rendering
*/
public preRender(): void {

// clear the current canvas
this.ctx.clearRect(0, 0, this.gameDimension.x, this.gameDimension.y);
// clear the current canvas (check performance when not clearing)
// this.ctx.clearRect(0, 0, this.gameDimension.x, this.gameDimension.y);

// check if a world should be rendered
if (this.worldRenderer) {
Expand Down Expand Up @@ -126,7 +124,7 @@ export class CanvasRenderer extends BasicRenderer {
this.entityRenderer.setWorldRenderer(this.worldRenderer);

// watit until the clusters has been created
return await this.worldRenderer.preRenderClusterTiles();
return await this.worldRenderer.preRenderLayers();
}

/**
Expand Down
217 changes: 84 additions & 133 deletions src/client/render/canvas/CanvasWorldRenderer.ts
Expand Up @@ -8,7 +8,7 @@
import { World } from '../../world/World';
import { Camera } from '../../camera/Camera';
import { WorldRenderer } from '../WorldRenderer';
import { Singleton, EventName, Binary, Vector2D } from '../../../shared';
import { Singleton, EventName, Binary, Vector2D, Dimension } from '../../../shared';
import { AssetStorage, AssetType, Image } from '../../asset';

/**
Expand All @@ -18,11 +18,10 @@ export class CanvasWorldRenderer extends Singleton implements WorldRenderer {

/**
* holder of all world relevant cluster images
* first dimension is the layer
* second dimension is the cluster x
* third dimension is the cluster y
* first dim: x
* second dim: y
*/
private renderedClusterCache: ImageBitmap[][][] = [];
private renderedLayerCache: ImageBitmap[][] = [];

/**
* the global asset storage
Expand Down Expand Up @@ -63,173 +62,125 @@ export class CanvasWorldRenderer extends Singleton implements WorldRenderer {
}

/**
* renders all clusters into a cluster cache to speed
* up the drawing process if the renderer
* render all tile layers into a cache bitmap to speed up rendering
*/
public async preRenderClusterTiles(): Promise<void> {
public async preRenderLayers(): Promise<void> {

// get the tilemap instance
const tilemap = this.world.getTileMap();
const clusterSize = this.world.getTileClusterSize();
const clusters = this.world.getTileCluster();

// create a tmp rendering context
// build a renderable context
const canvas = document.createElement('canvas');
canvas.width = tilemap.getDimension().x * clusterSize;
canvas.height = tilemap.getDimension().y * clusterSize;
const ctx = canvas.getContext('2d');

// promise stack for tile rendering
const clusterRenderPromiseStack: Array<Promise<any>> = [];
// iterate through the different layers
const map = this.world.getGeneratedWorld();
const mapWidth = map[0].length;
const mapHeight = map[0][0].length;

// iterate through the clusters
clusters.forEach((xCluster, layer) => {
// tile size
const tileDimension = this.world.getTileMap().getDimension();
canvas.width = tileDimension.x;
canvas.height = tileDimension.y;

// check if the array is capable of storing the layer
if (!Array.isArray(this.renderedClusterCache[layer]))
this.renderedClusterCache[layer] = [];
// render stack
const renderConvertPromiseStack: Array<Promise<void>> = [];

// iterate through the x cluster
xCluster.forEach((yCluster, xCoordinate) => {
// iterate through the x and y axis
for (let x = 0; x < mapWidth; x++) {

// check if the array is capable of storing the x coordinate
if (!Array.isArray(this.renderedClusterCache[layer][xCoordinate]))
this.renderedClusterCache[layer][xCoordinate] = [];
// y axis
for (let y = 0; y < mapHeight; y++) {

// now the y coordinate
yCluster.forEach((tiles, yCoordinate) => {
// get the tile numbers for this position
const positionVector = Vector2D.from(x, y);
const tileNumbers = this.world.getTileNumbersForPosition(positionVector);

// store the rendered cluster
clusterRenderPromiseStack.push(this.renderTmpCluster(
tiles, canvas, ctx, clusterSize
).then((clusterImg) => {
// clear the canvas context
ctx.clearRect(0, 0, tileDimension.x, tileDimension.y);

this.renderedClusterCache[layer][xCoordinate][yCoordinate] = clusterImg;
}));
// draw the tiles
tileNumbers.forEach((tile, layer) => {

});
});
});
// if the tile number is smaller then 0 ignore it
if (tile < 0) return;

// await the void promise
return Promise.all(clusterRenderPromiseStack).then(() => { return; });
}
// get the image from the asset storage
const tileName = `${this.world.getName()}[${tile}]`;
const tileImage = this.assetStorage.getAsset<Image>(
tileName, AssetType.Image
).getData() as ImageBitmap;

/**
* render the world!
*/
public render(): void {

// generate clusters and display a cluster of one or many tiles
// are visible by the active camera
const tilemap = this.world.getTileMap();

// iterate through the layers
for (let layer = 0; layer < tilemap.getLayerCount(); layer++) {

// y coordinate
for (const xCluster of this.renderedClusterCache[layer]) {

// fetch the coordinate
const xCoordinate = this.renderedClusterCache[layer].indexOf(xCluster);
// draw the tile
ctx.drawImage(
tileImage, 0, 0
);
});

// x coordinate
for (const clusterTileImage of this.renderedClusterCache[layer][xCoordinate]) {
// save the image
renderConvertPromiseStack.push(
createImageBitmap(Binary.dataUriToBlob(canvas.toDataURL()))
.then((bitmap) => {

// fetch the coordinate
const yCoordinate = this.renderedClusterCache[layer][xCoordinate].indexOf(clusterTileImage);
// array accessable
if (!Array.isArray(this.renderedLayerCache[x])) {
this.renderedLayerCache[x] = [];
}

// get information to render the cluster
// calculate the target position for the
// cluster tile and add the camera scale
const positionVector = Vector2D.from(
xCoordinate * clusterTileImage.width,
yCoordinate * clusterTileImage.height
);

// get the position camera based
const cameraPosition = this.camera.translatePosition(positionVector);

// get the cluster width and height including camera scale
const sizeVector = Vector2D.from(
clusterTileImage.width, clusterTileImage.height
).multiply(this.camera.getScaleVector());

// draw it!
this.ctx.drawImage(
clusterTileImage,
0, 0,
clusterTileImage.width, clusterTileImage.height,
cameraPosition.x, cameraPosition.y,
sizeVector.x, sizeVector.y
);
}
// save the bitmap in the cache
this.renderedLayerCache[x][y] = bitmap;
})
);
}

}

// await the rendering process
return Promise.all(renderConvertPromiseStack).then(() => { return; });
}

/**
* renders a given tile number array on a temp rendering context
*
* @param tileNumber the tile numbers to render
* @param ctx the tmp rendering context
* render the world!
*/
private async renderTmpCluster(
tileNumber: number[],
canvas: HTMLCanvasElement,
ctx: CanvasRenderingContext2D,
clusterSize: number
): Promise<ImageBitmap> {

// clear the tmp canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
public render(): void {

// helper var to increment the y axis
let yHelper = 0;
// iterate through the different layers
const map = this.world.getGeneratedWorld();
const mapWidth = map[0].length;
const mapHeight = map[0][0].length;

if(tileNumber.length / 4 !== 4) {
console.log(tileNumber);
}
// iterate through the x and y axis
for (let x = 0; x < mapWidth; x++) {

// iterate through the tiles
tileNumber.forEach((tile, index) => {
// y axis
for (let y = 0; y < mapHeight; y++) {

// get tile x coordinate
const xHelper = index % clusterSize;
// get the multilayer image
const tileImage = this.renderedLayerCache[x][y];

// draw the tile
const assetName = `${this.world.getTileMap().getName()}[${tile}]`;
// get information to render the cluster
// calculate the target position for the
// cluster tile and add the camera scale
const positionVector = Vector2D.from(
x * tileImage.width,
y * tileImage.height
);

// check if the asset is available
if (this.assetStorage.hasAsset(assetName, AssetType.Image)) {
const tileImage = this.assetStorage.getAsset<Image>(
assetName, AssetType.Image
).getData() as ImageBitmap;
// get the position camera based
const cameraPosition = this.camera.translatePosition(positionVector);

// increase y
if (Math.floor(index / clusterSize) > yHelper) {
yHelper++;
}
// get the cluster width and height including camera scale
const sizeVector = Vector2D.from(
tileImage.width, tileImage.height
).multiply(this.camera.getScaleVector());

// draw the tile on the tmp canvas context
ctx.drawImage(
// draw it!
this.ctx.drawImage(
tileImage,
0, 0,
tileImage.width, tileImage.height,
xHelper * tileImage.width,
yHelper * tileImage.height,
tileImage.width, tileImage.height
cameraPosition.x, cameraPosition.y,
sizeVector.x, sizeVector.y
);
}
});

// take the canvas picture as cluster image
const clusterImage = canvas.toDataURL();
}

// convert it to an imagebitmap
return createImageBitmap(Binary.dataUriToBlob(clusterImage));
}

}

0 comments on commit a06cf1f

Please sign in to comment.