import {compose, EventEmitter, Property} from '@avocado/core'; import {hasGraphics, Image} from '@avocado/graphics'; import {Rectangle, Vector} from '@avocado/math'; import {shapeFromJSON} from '@avocado/physics'; import {Resource} from '@avocado/resource'; const decorate = compose( EventEmitter, Property('image', { track: true, }), Vector.Mixin('tileSize', 'tileWidth', 'tileHeight', { default: [0, 0], }), ); export class Tileset extends decorate(Resource) { constructor(json) { super(); this._geometry = {}; this.subimages = []; if ('undefined' !== typeof json) { this.fromJSON(json); } } destroy() { this.subimages.forEach((subimage) => { subimage.destroy(); }); this.subimages = []; } fromJSON(json) { let promise; if (json.geometry) { for (const i in json.geometry) { const shapeJSON = json.geometry[i]; this._geometry[i] = shapeFromJSON(shapeJSON); } } if (json.tileSize) { this.tileSize = json.tileSize; } if (hasGraphics && json.imageUri) { Image.load(json.imageUri).then((image) => { this.image = image; }); } } geometry(index) { return this._geometry[index]; } get image() { return super.image; } set image(image) { this.recalculateSubimages(image); super.image = image; } recalculateSubimages(image) { if (!image) { return; } const tileSize = this.tileSize; if (Vector.isZero(tileSize)) { return; } this.destroy(); const grid = Vector.div(image.size, tileSize); const rectangle = Rectangle.compose([0, 0], tileSize); for (let j = 0; j < grid[1]; ++j) { for (let i = 0; i < grid[0]; ++i) { const subimage = image.subimage(rectangle); this.subimages.push(subimage); rectangle[0] += tileSize[0]; } rectangle[0] = 0; rectangle[1] += tileSize[1]; } } subimage(index) { return this.subimages[index]; } get tileSize() { return super.tileSize; } set tileSize(tileSize) { super.tileSize = tileSize; this.recalculateSubimages(this.image); } toJSON() { return { tileSize: this.tileSize, imageUri: this.image.uri, } } }