UNPKG

@spearwolf/twopoint5d

Version:

a library to create 2.5d realtime graphics and pixelart with three.js

247 lines 8.2 kB
import { emit, eventize, retain } from '@spearwolf/eventize'; import { batch, createEffect, createSignal, Signal, touch } from '@spearwolf/signalize'; import { ImageLoader } from 'three'; import { TextureCoords } from './TextureCoords.js'; import { TextureFactory } from './TextureFactory.js'; import { TexturePackerJson } from './TexturePackerJson.js'; import { TileSet } from './TileSet.js'; const cmpTexClasses = (a, b) => { if (a === b) { return true; } return `${a?.join() ?? ''}` === `${b?.join() ?? ''}`; }; const cmpTexCoords = (a, b) => { if (a === b) { return true; } if (a && b) { return (a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height && a.flip === b.flip && a.parent === b.parent); } return false; }; const cmpTileSetOptions = (a, b) => { if (a === b) { return true; } if (a && b) { return (a.tileWidth === b.tileWidth && a.tileHeight === b.tileHeight && a.margin === b.margin && a.spacing === b.spacing && a.padding === b.padding && a.tileCount === b.tileCount && a.firstId === b.firstId); } return false; }; export class TextureResource { static fromImage(id, imageUrl, textureClasses) { const resource = new TextureResource(id, 'image'); batch(() => { resource.imageUrl = imageUrl; resource.textureClasses = textureClasses?.splice(0); }); return resource; } static fromTileSet(id, imageUrl, tileSetOptions, textureClasses) { const resource = new TextureResource(id, 'tileset'); batch(() => { resource.imageUrl = imageUrl; resource.#tileSetOptions = createSignal(tileSetOptions, { compare: cmpTileSetOptions }); resource.#tileSet = createSignal(); resource.#atlas = createSignal(); resource.textureClasses = textureClasses?.splice(0); }); return resource; } static fromAtlas(id, atlasUrl, overrideImageUrl, textureClasses) { const resource = new TextureResource(id, 'atlas'); batch(() => { resource.#atlasUrl = createSignal(atlasUrl); resource.#atlasJson = createSignal(); resource.#atlas = createSignal(); resource.#overrideImageUrl = createSignal(overrideImageUrl); resource.textureClasses = textureClasses?.splice(0); }); return resource; } #atlasUrl; #atlasJson; #overrideImageUrl; #atlas; #tileSetOptions; #tileSet; #textureClasses; #imageUrl; #imageCoords; #textureFactory; #texture; #renderer; get imageUrl() { return this.#imageUrl.value; } set imageUrl(val) { this.#imageUrl.set(val); } get imageCoords() { return this.#imageCoords.value; } set imageCoords(val) { this.#imageCoords.set(val); } get atlasUrl() { return this.#atlasUrl?.value; } set atlasUrl(value) { this.#atlasUrl?.set(value); } get atlasJson() { return this.#atlasJson?.value; } set atlasJson(value) { this.#atlasJson?.set(value); } get overrideImageUrl() { return this.#overrideImageUrl?.value; } set overrideImageUrl(value) { this.#overrideImageUrl?.set(value); } get atlas() { return this.#atlas?.value; } set atlas(value) { this.#atlas?.set(value); } get tileSetOptions() { return this.#tileSetOptions?.value; } set tileSetOptions(value) { this.#tileSetOptions?.set(value); } get tileSet() { return this.#tileSet?.value; } set tileSet(value) { this.#tileSet?.set(value); } get textureClasses() { return this.#textureClasses.value; } set textureClasses(value) { if (Array.isArray(value) && value.length === 0) { value = undefined; } this.#textureClasses.set(value); } get textureFactory() { return this.#textureFactory.value; } set textureFactory(value) { this.#textureFactory.set(value); } get texture() { return this.#texture.value; } set texture(value) { this.#texture.set(value); } get renderer() { return this.#renderer.value; } set renderer(value) { this.#renderer.set(value); } #load; constructor(id, type) { this.#textureClasses = createSignal(undefined, { compare: cmpTexClasses }); this.#imageUrl = createSignal(); this.#imageCoords = createSignal(undefined, { compare: cmpTexCoords }); this.#textureFactory = createSignal(); this.#texture = createSignal(); this.#renderer = createSignal(); this.refCount = 0; this.#load = false; eventize(this); this.id = id; this.type = type; retain(this, ['imageCoords', 'atlas', 'tileSet', 'texture']); } rendererChanged(renderer) { this.renderer = renderer; } load() { if (!this.#load) { this.#load = true; this.#imageCoords.onChange((value) => { emit(this, 'imageCoords', value); }); this.#atlas?.onChange((value) => { emit(this, 'atlas', value); }); this.#tileSet?.onChange((value) => { emit(this, 'tileSet', value); }); this.#texture.onChange((value) => { emit(this, 'texture', value); }); createEffect(() => { let texture; if (this.textureFactory && this.imageUrl) { new ImageLoader().loadAsync(this.imageUrl).then((image) => { batch(() => { this.imageCoords = new TextureCoords(0, 0, image.width, image.height); texture = this.textureFactory.create(image); texture.name = this.id; this.texture = texture; }); }); } return () => { if (texture) { console.log('dispose texture', texture); texture.dispose(); } }; }, [this.#textureFactory, this.#imageUrl]); if (this.tileSetOptions) { createEffect(() => { if (this.imageCoords && this.tileSetOptions) { this.tileSet = new TileSet(this.imageCoords, this.tileSetOptions); } }, [this.#imageCoords, this.#tileSetOptions]); } if (this.atlasUrl) { createEffect(() => { if (this.atlasUrl) { fetch(this.atlasUrl) .then((response) => response.json()) .then((atlasJson) => { this.atlasJson = atlasJson; }); } }, [this.#atlasUrl]); createEffect(() => { if (this.atlasJson) { this.imageUrl = this.overrideImageUrl ?? this.atlasJson.meta.image; } }, [this.#atlasJson, this.#overrideImageUrl]); createEffect(() => { if (this.atlasJson && this.imageCoords) { const [atlas] = TexturePackerJson.parse(this.atlasJson, this.imageCoords); this.atlas = atlas; } }, [this.#atlasJson, this.#imageCoords]); touch(this.#atlasUrl); } createEffect(() => { if (this.renderer) { this.textureFactory = new TextureFactory(this.#renderer.get(), this.#textureClasses.get()); } }); } return this; } } //# sourceMappingURL=TextureResource.js.map