UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

269 lines (266 loc) 8.48 kB
import { ADDRESS_CLAMP_TO_EDGE, PIXELFORMAT_RGBA8, PIXELFORMAT_RGB8, TEXTURETYPE_RGBM, TEXTURETYPE_DEFAULT } from '../../platform/graphics/constants.js'; import { Texture } from '../../platform/graphics/texture.js'; import { Asset } from '../asset/asset.js'; import { ResourceHandler } from './handler.js'; class CubemapHandler extends ResourceHandler { constructor(app){ super(app, 'cubemap'); this._device = app.graphicsDevice; this._registry = app.assets; this._loader = app.loader; } load(url, callback, asset) { this.loadAssets(asset, callback); } open(url, data, asset) { return asset ? asset.resource : null; } patch(asset, registry) { this.loadAssets(asset, (err, result)=>{ if (err) { registry.fire('error', asset); registry.fire(`error:${asset.id}`, err, asset); asset.fire('error', asset); } }); } getAssetIds(cubemapAsset) { const result = []; result[0] = cubemapAsset.file; if ((cubemapAsset.loadFaces || !cubemapAsset.file) && cubemapAsset.data && cubemapAsset.data.textures) { for(let i = 0; i < 6; ++i){ result[i + 1] = cubemapAsset.data.textures[i]; } } else { result[1] = result[2] = result[3] = result[4] = result[5] = result[6] = null; } return result; } compareAssetIds(assetIdA, assetIdB) { if (assetIdA && assetIdB) { if (parseInt(assetIdA, 10) === assetIdA || typeof assetIdA === 'string') { return assetIdA === assetIdB; } return assetIdA.url === assetIdB.url; } return assetIdA !== null === (assetIdB !== null); } update(cubemapAsset, assetIds, assets) { const assetData = cubemapAsset.data || {}; const oldAssets = cubemapAsset._handlerState.assets; const oldResources = cubemapAsset._resources; let tex, mip, i; const resources = [ null, null, null, null, null, null, null ]; const getType = function() { if (assetData.hasOwnProperty('type')) { return assetData.type; } if (assetData.hasOwnProperty('rgbm')) { return assetData.rgbm ? TEXTURETYPE_RGBM : TEXTURETYPE_DEFAULT; } return null; }; if (!cubemapAsset.loaded || assets[0] !== oldAssets[0]) { if (assets[0]) { tex = assets[0].resource; if (tex.cubemap) { for(i = 0; i < 6; ++i){ resources[i + 1] = new Texture(this._device, { name: `${cubemapAsset.name}_prelitCubemap${tex.width >> i}`, cubemap: true, type: getType() || tex.type, width: tex.width >> i, height: tex.height >> i, format: tex.format, levels: [ tex._levels[i] ], addressU: ADDRESS_CLAMP_TO_EDGE, addressV: ADDRESS_CLAMP_TO_EDGE, mipmaps: i === 0 }); } } else { resources[1] = tex; } } } else { resources[1] = oldResources[1] || null; resources[2] = oldResources[2] || null; resources[3] = oldResources[3] || null; resources[4] = oldResources[4] || null; resources[5] = oldResources[5] || null; resources[6] = oldResources[6] || null; } const faceAssets = assets.slice(1); if (!cubemapAsset.loaded || !this.cmpArrays(faceAssets, oldAssets.slice(1))) { if (faceAssets.indexOf(null) === -1) { const faceTextures = faceAssets.map((asset)=>{ return asset.resource; }); const faceLevels = []; for(mip = 0; mip < faceTextures[0]._levels.length; ++mip){ faceLevels.push(faceTextures.map((faceTexture)=>{ return faceTexture._levels[mip]; })); } const format = faceTextures[0].format; const faces = new Texture(this._device, { name: `${cubemapAsset.name}_faces`, cubemap: true, type: getType() || faceTextures[0].type, width: faceTextures[0].width, height: faceTextures[0].height, format: format === PIXELFORMAT_RGB8 ? PIXELFORMAT_RGBA8 : format, mipmaps: assetData.mipmaps ?? true, levels: faceLevels, minFilter: assetData.hasOwnProperty('minFilter') ? assetData.minFilter : faceTextures[0].minFilter, magFilter: assetData.hasOwnProperty('magFilter') ? assetData.magFilter : faceTextures[0].magFilter, anisotropy: assetData.hasOwnProperty('anisotropy') ? assetData.anisotropy : 1, addressU: ADDRESS_CLAMP_TO_EDGE, addressV: ADDRESS_CLAMP_TO_EDGE }); resources[0] = faces; } } else { resources[0] = oldResources[0] || null; } if (!this.cmpArrays(resources, oldResources)) { cubemapAsset.resources = resources; cubemapAsset._handlerState.assetIds = assetIds; cubemapAsset._handlerState.assets = assets; for(i = 0; i < oldResources.length; ++i){ if (oldResources[i] !== null && resources.indexOf(oldResources[i]) === -1) { oldResources[i].destroy(); } } } for(i = 0; i < oldAssets.length; ++i){ if (oldAssets[i] !== null && assets.indexOf(oldAssets[i]) === -1) { oldAssets[i].unload(); } } } cmpArrays(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } for(let i = 0; i < arr1.length; ++i){ if (arr1[i] !== arr2[i]) { return false; } } return true; } resolveId(value) { const valueInt = parseInt(value, 10); return valueInt === value || valueInt.toString() === value ? valueInt : value; } loadAssets(cubemapAsset, callback) { if (!cubemapAsset.hasOwnProperty('_handlerState')) { cubemapAsset._handlerState = { assetIds: [ null, null, null, null, null, null, null ], assets: [ null, null, null, null, null, null, null ] }; } const self = this; const assetIds = self.getAssetIds(cubemapAsset); const assets = [ null, null, null, null, null, null, null ]; const loadedAssetIds = cubemapAsset._handlerState.assetIds; const loadedAssets = cubemapAsset._handlerState.assets; const registry = self._registry; let awaiting = 7; const onLoad = function(index, asset) { assets[index] = asset; awaiting--; if (awaiting === 0) { self.update(cubemapAsset, assetIds, assets); callback(null, cubemapAsset.resources); } }; const onError = function(index, err, asset) { callback(err); }; const processTexAsset = function(index, texAsset) { if (texAsset.loaded) { onLoad(index, texAsset); } else { registry.once(`load:${texAsset.id}`, onLoad.bind(self, index)); registry.once(`error:${texAsset.id}`, onError.bind(self, index)); if (!texAsset.loading) { registry.load(texAsset); } } }; let texAsset; for(let i = 0; i < 7; ++i){ const assetId = this.resolveId(assetIds[i]); if (!assetId) { onLoad(i, null); } else if (self.compareAssetIds(assetId, loadedAssetIds[i])) { processTexAsset(i, loadedAssets[i]); } else if (parseInt(assetId, 10) === assetId) { texAsset = registry.get(assetId); if (texAsset) { processTexAsset(i, texAsset); } else { setTimeout(((index, assetId_)=>{ const texAsset = registry.get(assetId_); if (texAsset) { processTexAsset(index, texAsset); } else { onError(index, `failed to find dependent cubemap asset=${assetId_}`); } }).bind(null, i, assetId)); } } else { const file = typeof assetId === 'string' ? { url: assetId, filename: assetId } : assetId; const data = file.url.search('.dds') === -1 ? { type: 'rgbp', addressu: 'clamp', addressv: 'clamp', mipmaps: false } : null; texAsset = new Asset(`${cubemapAsset.name}_part_${i}`, 'texture', file, data); registry.add(texAsset); processTexAsset(i, texAsset); } } } } export { CubemapHandler };