@spearwolf/twopoint5d
Version:
a library to create 2.5d realtime graphics and pixelart with three.js
247 lines • 8.2 kB
JavaScript
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