import BASISLoader from './BASISLoader';
import WorkedBASIS from './worker';
/**
* @example
* // 初始化压缩纹理插件
* Tiny.plugins.compressedTexture.init(app.renderer);
* // 加载转换器并执行转换
* Tiny.plugins.compressedTexture.WorkedBASISLoader.loadAndRunTranscoder({
* // basis_transcoder 的 js 及 wasm 文件路径,可使用相对路径。
* // 加载后的完整链接为:./libs/basis_transcoder.js 和 ./libs/basis_transcoder.wasm
* path: './libs',
* // Worker 线程数,默认为 2,最高 8,可按资源数量设置
* threads: 6,
* })
* .then(function() {
* const loader = new Tiny.loaders.Loader();
*
* loader
* .add({
* name: 'xxx',
* url: './res/xxx.png',
* // 设置 metadata.useFormat 为 basis,告诉加载器明确只使用 BASIS 纹理
* metadata: { useCompressedTexture: true, useFormat: 'basis' },
* })
* .load((loaderInstance, resources) => {
* });
* })
* .catch(e => {
* console.log(e);
* });
*
* @memberof Tiny.plugins.compressedTexture
* @extends Tiny.plugins.compressedTexture.BASISLoader
*/
class WorkedBASISLoader extends BASISLoader {
_loadAsync(buffer) {
// const startTime = performance.now();
const pool = BASISLoader.BASIS_BINDING;
const config = {
genMip: true,
rgbaFormat: BASISLoader.RGBA_FORMAT.basis,
rgbFormat: BASISLoader.RGB_FORMAT.basis,
transfer: true,
};
return pool
.transcode(buffer, config)
.then(({ width, height, buffer, hasAlpha, mipmaps }) => {
const srcBuffer = new Uint8Array(buffer);
const target = hasAlpha ? BASISLoader.RGBA_FORMAT : BASISLoader.RGB_FORMAT;
const name = target.name.replace('COMPRESSED_', '');
const dest = this._image;
// console.log('[WorkedBASISLoader] Total transcoding time:', performance.now() - startTime);
dest._getLevelSize = (level) => {
return mipmaps[level].size;
};
return dest.init(dest.src, srcBuffer, 'BASIS|' + name, width, height, 1, target.native);
})
.catch(e => {
console.error(e);
});
}
}
/**
* 加载并执行 Transcoder
*
* @static
* @param {object} opts
* @param {string} opts.path - BASIS transcoder 的 JS/wasm 文件链接,文件名必须是 basis_transcoder.js 和 basis_transcoder.wasm
* @param {number} [opts.threads=2] - Worker 线程数
* @return {Promise}
*/
WorkedBASISLoader.loadAndRunTranscoder = function({ path, ...opts }) {
return new Promise(function(resolve, reject) {
const loader = new Tiny.loaders.Loader();
const jsName = 'basis_transcoder_js';
const wasmName = 'basis_transcoder_wasm';
const uri = path.replace(/(.*)\/$/, '$1');
loader
.add([{
name: jsName,
url: `${uri}/basis_transcoder.js`,
loadType: Tiny.loaders.Resource.LOAD_TYPE.XHR,
xhrType: Tiny.loaders.Resource.XHR_RESPONSE_TYPE.TEXT,
}, {
name: wasmName,
url: `${uri}/basis_transcoder.wasm`,
loadType: Tiny.loaders.Resource.LOAD_TYPE.XHR,
xhrType: Tiny.loaders.Resource.XHR_RESPONSE_TYPE.BUFFER,
}])
.load(function(_, resources) {
const { data: js } = resources[jsName];
const { data: wasm } = resources[wasmName];
WorkedBASISLoader.runTranscoder({
jsSource: js,
wasmSource: wasm,
...opts,
});
resolve();
})
.on('complete', function(loader, resource) {
this.reset();
})
.on('error', function(e) {
reject(e);
});
});
};
/**
* 执行 Transcoder
*
* @static
* @param {object} opts
* @param {string} opts.jsSource - BASIS transcoder 的 JS 文件内容
* @param {ArrayBuffer} opts.wasmSource - BASIS transcoder 的 wasm 文件内容
* @param {number} [opts.threads=2] - Worker 线程数
* @return {Promise}
*/
WorkedBASISLoader.runTranscoder = function({ jsSource, wasmSource, threads = 2 }) {
const trans = new WorkedBASIS.TranscoderWorkerPool(threads);
BASISLoader.bindTranscoder.call(this, trans);
BASISLoader._useWorker = true;
return trans.init(jsSource, wasmSource);
};
export default WorkedBASISLoader;