UNPKG

blaze-2d

Version:

A fast and simple WebGL 2 2D game engine written in TypeScript

214 lines 7.71 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { vec2 } from "gl-matrix"; import Logger from "../logger"; import Texture from "./texture"; const colorBlockSize = 5; const padding = 5; /** * Combines {@link Texture}s into one single image using an offscreen canvas. * * If a {@link Texture} is added to the atlas that has no image then a 1x1 pixel is used with the color of the texture. * * The size of the atlas should be no larger than `MAX_TEXTURE_SIZE` to insure the atlas can be stored on the GPU. * * Also provides an api to get the locations of textures on the atlas. */ export default class TextureAtlas extends Texture { constructor(size) { super(); this.textures = new Map(); this.size = size; this.canvas = document.createElement("canvas"); this.canvas.height = size; this.canvas.width = size; this.ctx = this.canvas.getContext("2d", { alpha: true }); } /** * Adds the given images to the atlas and then refreshes the atlas. * * @param images The paths to the images to add * @returns Wether or not the images were added */ addImages(...images) { return __awaiter(this, void 0, void 0, function* () { const textures = images.map(() => { return new Texture(); }); // try to load images try { yield Promise.all(textures.map((tex, i) => tex.loadImage(images[i]))); } catch (error) { Logger.error("TextureAtlas", "An error occured while loading images.", error); return false; } yield this.addTextures(...textures); return true; }); } /** * Adds a texture to the atlas. * * @param texture The texture to add * @param refreshAtlas Wether or not to refresh the atlas once the texture has been added * @returns Wether or not the texture was added to the atlas */ addTexture(texture, refreshAtlas = false) { if (this.textures.has(texture)) return true; this.textures.set(texture, { texture, tl: vec2.create(), br: vec2.create(), }); if (refreshAtlas) { this.refreshAtlas(); } return true; } /** * Adds the given textures to the atlas and then refreshes the atlas. * * @param textures The textures to add. * @returns The promise returned by `this.refreshAtlas()` */ addTextures(...textures) { for (const t of textures) { this.addTexture(t); } return this.refreshAtlas(); } /** * Removes a texture from the atlas. * * @param texture The texture to remove * @param refreshAtlas Wether or not to refresh the atlas once the texture has been removed * @returns Wether or not the texture was removed from the atlas */ removeTexture(texture, refreshAtlas = false) { this.textures.delete(texture); if (refreshAtlas) { this.refreshAtlas(); } return true; } /** * Gets the location ({@link TextureAtlasImage}) of the texture on the atlas. * * @param texture The texture to find * @returns The {@link TextureAtlasImage} of the texture on the atlas or undefined */ getTexture(texture) { return this.textures.get(texture); } /** * Gets all the textures on the atlas as an array. * * @returns An array of all textures on the atlas */ getAllTextures() { return Array.from(this.textures.values()); } /** * Packs all textures in the atlas together, draws them to the canvas and loads the canvas as a data URL to `this.image`. * * @returns A promise that resolves once the image has loaded or rejects if there is an error while loading the atlas image. */ refreshAtlas() { this.packTextures(); this.drawTexturesOnCanvas(); return this.loadImage(); } /** * Loads the atlas' canvas into `this.image`. * * @returns A promise that resolves once the image has loaded or rejects if there is an error while loading the image. */ loadImage() { return super.loadImage(this.canvas.toDataURL()); } /** * Packs all textures in the atlas onto it's canvas. * * It then loads the canvas as a data URL into `this.image` using `this.loadImage`. */ packTextures() { const textures = this.getAllTextures(); const maxWidth = this.size; let rowHeight = 0; let row = 0; let col = 0; while (textures.length > 0) { const { i, t } = this.findTallestTexture(textures); textures.splice(i, 1); const image = t.texture.image; const width = image ? image.width : colorBlockSize; const height = image ? image.height : colorBlockSize; if (height > rowHeight || col + width > maxWidth) { row += rowHeight + padding; rowHeight = height; col = 0; } t.tl = vec2.fromValues(col, row); t.br = vec2.fromValues(col + width, row + height); col += width + padding; } } /** * Draws all textures stored in the atlas onto the canvas. * * If `this.packTextures` has not been called beforehand then all textures will be drawn over each other or in undesired positions. */ drawTexturesOnCanvas() { const textures = this.getAllTextures(); this.ctx.clearRect(0, 0, this.size, this.size); for (const t of textures) { if (!t.texture.image) { // when texture has no image substitute with 5x5 pixel of textures color this.ctx.fillStyle = t.texture.color.hex; this.ctx.fillRect(t.tl[0], t.tl[1], colorBlockSize, colorBlockSize); } else { this.ctx.drawImage(t.texture.image, t.tl[0], t.tl[1]); } } } /** * Finds the tallest texture in the given list of textures. * * @param textures The list of textures to search * @returns The tallest texture and it's index in `textures` */ findTallestTexture(textures) { let maxHeight = 0; let tallestTexture; let tallestIndex = 0; for (let i = 0; i < textures.length; i++) { const t = textures[i]; const h = t.texture.image ? t.texture.image.height || colorBlockSize : colorBlockSize; if (h > maxHeight) { maxHeight = h; tallestTexture = t; tallestIndex = i; } } return { i: tallestIndex, t: tallestTexture }; } /** * Gets the size of the atlas image. * * @returns The size of the atlas image */ getSize() { return this.size; } } //# sourceMappingURL=atlas.js.map