From 28af560d4c15b92632044678aaf310bc07f2e0d2 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 6 Jan 2024 16:34:49 -0600 Subject: [PATCH] feat(texture): move texture loading into worker (#32) --- src/lib/texture/TextureManager.ts | 40 +++++++------- src/lib/texture/loader/TextureLoader.ts | 25 +++++++++ src/lib/texture/loader/TextureLoaderWorker.ts | 52 +++++++++++++++++++ src/lib/texture/loader/types.ts | 16 ++++++ src/lib/texture/loader/worker.ts | 3 ++ 5 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 src/lib/texture/loader/TextureLoader.ts create mode 100644 src/lib/texture/loader/TextureLoaderWorker.ts create mode 100644 src/lib/texture/loader/types.ts create mode 100644 src/lib/texture/loader/worker.ts diff --git a/src/lib/texture/TextureManager.ts b/src/lib/texture/TextureManager.ts index c200f72..11a169c 100644 --- a/src/lib/texture/TextureManager.ts +++ b/src/lib/texture/TextureManager.ts @@ -1,9 +1,10 @@ import * as THREE from 'three'; -import { Blp, BLP_IMAGE_FORMAT } from '@wowserhq/format'; +import { BLP_IMAGE_FORMAT } from '@wowserhq/format'; import ManagedCompressedTexture from './ManagedCompressedTexture.js'; import ManagedDataTexture from './ManagedDataTexture.js'; -import FormatManager from '../FormatManager.js'; +import TextureLoader from './loader/TextureLoader.js'; import { AssetHost, normalizePath } from '../asset.js'; +import { TextureSpec } from './loader/types.js'; const THREE_TEXTURE_FORMAT: Record = { [BLP_IMAGE_FORMAT.IMAGE_DXT1]: THREE.RGBA_S3TC_DXT1_Format, @@ -14,12 +15,11 @@ const THREE_TEXTURE_FORMAT: Record(); #loading = new Map>(); @@ -27,7 +27,7 @@ class TextureManager { constructor(options: TextureManagerOptions) { this.#host = options.host; - this.#formatManager = options.formatManager ?? new FormatManager({ host: options.host }); + this.#loader = new TextureLoader({ host: options.host }); } get( @@ -102,50 +102,48 @@ class TextureManager { minFilter: THREE.MinificationTextureFilter, magFilter: THREE.MagnificationTextureFilter, ) { - let blp: Blp; + let spec: TextureSpec; try { - blp = await this.#formatManager.get(path, Blp); + spec = await this.#loader.loadSpec(path); } catch (error) { this.#loading.delete(refId); throw error; } - const images = blp.getImages(); - const firstImage = images[0]; - const imageFormat = firstImage.format; + const specFormat = spec.format; - const threeFormat = THREE_TEXTURE_FORMAT[imageFormat]; + const threeFormat = THREE_TEXTURE_FORMAT[specFormat]; if (threeFormat === undefined) { this.#loading.delete(refId); - throw new Error(`Unsupported texture format: ${imageFormat}`); + throw new Error(`Unsupported texture format: ${specFormat}`); } let texture: ManagedCompressedTexture | ManagedDataTexture; if ( - imageFormat === BLP_IMAGE_FORMAT.IMAGE_DXT1 || - imageFormat === BLP_IMAGE_FORMAT.IMAGE_DXT3 || - imageFormat === BLP_IMAGE_FORMAT.IMAGE_DXT5 + specFormat === BLP_IMAGE_FORMAT.IMAGE_DXT1 || + specFormat === BLP_IMAGE_FORMAT.IMAGE_DXT3 || + specFormat === BLP_IMAGE_FORMAT.IMAGE_DXT5 ) { texture = new ManagedCompressedTexture( this, refId, null, - blp.width, - blp.height, + spec.width, + spec.height, threeFormat as THREE.CompressedPixelFormat, ); - } else if (imageFormat === BLP_IMAGE_FORMAT.IMAGE_ABGR8888) { + } else if (specFormat === BLP_IMAGE_FORMAT.IMAGE_ABGR8888) { texture = new ManagedDataTexture( this, refId, null, - blp.width, - blp.height, + spec.width, + spec.height, threeFormat as THREE.PixelFormat, ); } - texture.mipmaps = images; + texture.mipmaps = spec.mipmaps; texture.wrapS = wrapS; texture.wrapT = wrapT; texture.minFilter = minFilter; diff --git a/src/lib/texture/loader/TextureLoader.ts b/src/lib/texture/loader/TextureLoader.ts new file mode 100644 index 0000000..d2c01de --- /dev/null +++ b/src/lib/texture/loader/TextureLoader.ts @@ -0,0 +1,25 @@ +import SceneWorkerController from '../../worker/SceneWorkerController.js'; +import { TextureSpec } from './types.js'; +import { AssetHost } from '../../asset.js'; + +const createWorker = () => + new Worker(new URL('./worker.js', import.meta.url), { + name: 'texture-loader', + type: 'module', + }); + +type TextureLoaderOptions = { + host: AssetHost; +}; + +class TextureLoader extends SceneWorkerController { + constructor(options: TextureLoaderOptions) { + super(createWorker, { host: options.host }); + } + + loadSpec(path: string): Promise { + return this.request('loadSpec', path); + } +} + +export default TextureLoader; diff --git a/src/lib/texture/loader/TextureLoaderWorker.ts b/src/lib/texture/loader/TextureLoaderWorker.ts new file mode 100644 index 0000000..37fdb40 --- /dev/null +++ b/src/lib/texture/loader/TextureLoaderWorker.ts @@ -0,0 +1,52 @@ +import { Blp } from '@wowserhq/format'; +import { TextureSpec } from './types.js'; +import SceneWorker from '../../worker/SceneWorker.js'; +import { AssetHost, loadAsset } from '../../asset.js'; + +type TextureLoaderWorkerOptions = { + host: AssetHost; +}; + +class TextureLoaderWorker extends SceneWorker { + #host: AssetHost; + + initialize(options: TextureLoaderWorkerOptions) { + this.#host = options.host; + } + + async loadSpec(path: string) { + const blpData = await loadAsset(this.#host, path); + const blp = new Blp().load(blpData); + + const images = blp.getImages(); + const format = images[0].format; + + const mipmaps = new Array(images.length); + const buffers = new Set(); + + for (let i = 0; i < images.length; i++) { + const image = images[i]; + + mipmaps[i] = { + width: image.width, + height: image.height, + data: image.data, + }; + + buffers.add(image.data.buffer); + } + + const spec: TextureSpec = { + width: blp.width, + height: blp.height, + format, + mipmaps, + }; + + const transfer = [...buffers]; + + return [spec, transfer]; + } +} + +export default TextureLoaderWorker; diff --git a/src/lib/texture/loader/types.ts b/src/lib/texture/loader/types.ts new file mode 100644 index 0000000..34d37f1 --- /dev/null +++ b/src/lib/texture/loader/types.ts @@ -0,0 +1,16 @@ +import { BLP_IMAGE_FORMAT } from '@wowserhq/format'; + +type TextureMipmapSpec = { + width: number; + height: number; + data: Uint8Array; +}; + +type TextureSpec = { + width: number; + height: number; + format: BLP_IMAGE_FORMAT; + mipmaps: TextureMipmapSpec[]; +}; + +export { TextureSpec }; diff --git a/src/lib/texture/loader/worker.ts b/src/lib/texture/loader/worker.ts new file mode 100644 index 0000000..af473a3 --- /dev/null +++ b/src/lib/texture/loader/worker.ts @@ -0,0 +1,3 @@ +import TextureLoaderWorker from './TextureLoaderWorker.js'; + +const worker = new TextureLoaderWorker();