|
|
|
|
|
|
|
|
* Utility class to manage import, export, and material management. |
|
|
* Utility class to manage import, export, and material management. |
|
|
* @category Asset Manager |
|
|
* @category Asset Manager |
|
|
*/ |
|
|
*/ |
|
|
export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> { |
|
|
|
|
|
|
|
|
export class AssetManager extends EventDispatcher<BaseEvent&{data?: ImportResult}, 'loadAsset'|'processStateUpdate'> { |
|
|
readonly viewer: ThreeViewer |
|
|
readonly viewer: ThreeViewer |
|
|
readonly importer: AssetImporter |
|
|
readonly importer: AssetImporter |
|
|
readonly exporter: AssetExporter |
|
|
readonly exporter: AssetExporter |
|
|
readonly materials: MaterialManager |
|
|
readonly materials: MaterialManager |
|
|
private _storage?: Cache | Storage |
|
|
private _storage?: Cache | Storage |
|
|
get storage() {return this._storage} |
|
|
|
|
|
|
|
|
get storage() { |
|
|
|
|
|
return this._storage |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
constructor(viewer: ThreeViewer, {simpleCache = false, storage}: AssetManagerOptions = {}) { |
|
|
constructor(viewer: ThreeViewer, {simpleCache = false, storage}: AssetManagerOptions = {}) { |
|
|
super() |
|
|
super() |
|
|
|
|
|
|
|
|
this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated) |
|
|
this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated) |
|
|
this._initCacheStorage(simpleCache, storage ?? true) |
|
|
this._initCacheStorage(simpleCache, storage ?? true) |
|
|
|
|
|
|
|
|
this.importer.addEventListener('processRaw', (event)=>{ |
|
|
|
|
|
// console.log('preprocess mat', mat) |
|
|
|
|
|
const mat = event.data as IMaterial |
|
|
|
|
|
if (!mat || !mat.isMaterial || !mat.uuid) return |
|
|
|
|
|
if (this.materials?.findMaterial(mat.uuid)) { |
|
|
|
|
|
console.warn('imported material uuid already exists, creating new uuid') |
|
|
|
|
|
mat.uuid = generateUUID() |
|
|
|
|
|
if (mat.userData.uuid) mat.userData.uuid = mat.uuid |
|
|
|
|
|
} |
|
|
|
|
|
// todo: check for name exists also |
|
|
|
|
|
this.materials.registerMaterial(mat) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
this.importer.addEventListener('processRawStart', (event)=>{ |
|
|
|
|
|
// console.log('preprocess mat', mat) |
|
|
|
|
|
const res = event.data! |
|
|
|
|
|
const options = event.options! as ProcessRawOptions |
|
|
|
|
|
// if (!res.assetType) { |
|
|
|
|
|
// if (res.isBufferGeometry) { // for eg stl todo |
|
|
|
|
|
// res = new Mesh(res, new MeshStandardMaterial()) |
|
|
|
|
|
// } |
|
|
|
|
|
// if (res.isObject3D) { |
|
|
|
|
|
// } |
|
|
|
|
|
// } |
|
|
|
|
|
if (res.isObject3D) { |
|
|
|
|
|
const cameras: Camera[] = [] |
|
|
|
|
|
const lights: Light[] = [] |
|
|
|
|
|
res.traverse((obj: any) => { |
|
|
|
|
|
if (obj.material) { |
|
|
|
|
|
const materials = Array.isArray(obj.material) ? obj.material : [obj.material] |
|
|
|
|
|
const newMaterials = [] |
|
|
|
|
|
for (const material of materials) { |
|
|
|
|
|
const mat = this.materials.convertToIMaterial(material, {createFromTemplate: options.replaceMaterials !== false}) || material |
|
|
|
|
|
mat.uuid = material.uuid |
|
|
|
|
|
mat.userData.uuid = material.uuid |
|
|
|
|
|
newMaterials.push(mat) |
|
|
|
|
|
} |
|
|
|
|
|
if (Array.isArray(obj.material)) obj.material = newMaterials |
|
|
|
|
|
else obj.material = newMaterials[0] |
|
|
|
|
|
} |
|
|
|
|
|
if (obj.isCamera) cameras.push(obj) |
|
|
|
|
|
if (obj.isLight) lights.push(obj) |
|
|
|
|
|
}) |
|
|
|
|
|
for (const camera of cameras) { |
|
|
|
|
|
if ((camera as PerspectiveCamera2).assetType === 'camera') continue |
|
|
|
|
|
// todo: OrthographicCamera |
|
|
|
|
|
if (!(camera as PerspectiveCamera).isPerspectiveCamera || !camera.parent || options.replaceCameras === false) { |
|
|
|
|
|
iCameraCommons.upgradeCamera.call(camera) |
|
|
|
|
|
} else { |
|
|
|
|
|
const newCamera: ICamera = (camera as any).iCamera ?? |
|
|
|
|
|
new PerspectiveCamera2('', this.viewer.canvas) |
|
|
|
|
|
if (camera === newCamera) continue |
|
|
|
|
|
camera.parent.children.splice(camera.parent.children.indexOf(camera), 1, newCamera) |
|
|
|
|
|
newCamera.parent = camera.parent as any |
|
|
|
|
|
newCamera.copy(camera as any) |
|
|
|
|
|
camera.parent = null |
|
|
|
|
|
;(newCamera as any).uuid = camera.uuid |
|
|
|
|
|
newCamera.userData.uuid = camera.uuid |
|
|
|
|
|
;(camera as any).iCamera = newCamera |
|
|
|
|
|
// console.log('replacing camera', camera, newCamera) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (const light of lights) { |
|
|
|
|
|
if ((light as ILight).assetType === 'light') continue |
|
|
|
|
|
if (!light.parent || options.replaceLights === false) { |
|
|
|
|
|
iLightCommons.upgradeLight.call(light) |
|
|
|
|
|
} else { |
|
|
|
|
|
const newLight: ILight|undefined = (light as any).iLight ?? |
|
|
|
|
|
(light as any).isDirectionalLight ? new DirectionalLight2() : |
|
|
|
|
|
(light as any).isPointLight ? new PointLight2() : |
|
|
|
|
|
(light as any).isSpotLight ? new SpotLight2() : |
|
|
|
|
|
(light as any).isAmbientLight ? new AmbientLight2() : |
|
|
|
|
|
(light as any).isHemisphereLight ? new HemisphereLight2() : |
|
|
|
|
|
(light as any).isRectAreaLight ? new RectAreaLight2() : |
|
|
|
|
|
undefined |
|
|
|
|
|
if (light === newLight || !newLight) continue |
|
|
|
|
|
light.parent.children.splice(light.parent.children.indexOf(light), 1, newLight) |
|
|
|
|
|
newLight.parent = light.parent as any |
|
|
|
|
|
newLight.copy(light as any) |
|
|
|
|
|
light.parent = null |
|
|
|
|
|
;(newLight as any).uuid = light.uuid |
|
|
|
|
|
newLight.userData.uuid = light.uuid |
|
|
|
|
|
;(light as any).iLight = newLight |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
iObjectCommons.upgradeObject3D.call(res) |
|
|
|
|
|
} else if (res.isMaterial) { |
|
|
|
|
|
iMaterialCommons.upgradeMaterial.call(res) |
|
|
|
|
|
// todo update res by generating new material? |
|
|
|
|
|
} else if (res.isTexture) { |
|
|
|
|
|
upgradeTexture.call(res) |
|
|
|
|
|
|
|
|
|
|
|
if (event?.options?.generateMipmaps !== undefined) |
|
|
|
|
|
res.generateMipmaps = event?.options.generateMipmaps |
|
|
|
|
|
if (!res.generateMipmaps && !res.isRenderTargetTexture) { // todo: do we need to check more? |
|
|
|
|
|
res.minFilter = res.minFilter === LinearMipmapLinearFilter ? LinearFilter : res.minFilter |
|
|
|
|
|
res.magFilter = res.magFilter === LinearMipmapLinearFilter ? LinearFilter : res.magFilter |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
// todo other asset/object types? |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this._setupObjectProcess() |
|
|
|
|
|
this._setupProcessState() |
|
|
this._addImporters() |
|
|
this._addImporters() |
|
|
this._addExporters() |
|
|
this._addExporters() |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async addAsset<T extends ImportResult = ImportResult>(assetOrPath?: string | IAsset | IAsset[] | File | File[], options?: ImportAddOptions): Promise<(T|undefined)[]> { |
|
|
|
|
|
|
|
|
async addAsset<T extends ImportResult = ImportResult>(assetOrPath?: string | IAsset | IAsset[] | File | File[], options?: ImportAddOptions): Promise<(T | undefined)[]> { |
|
|
if (!this.importer || !this.viewer) return [] |
|
|
if (!this.importer || !this.viewer) return [] |
|
|
const imported = await this.importer.import<T>(assetOrPath, options) |
|
|
const imported = await this.importer.import<T>(assetOrPath, options) |
|
|
if (!imported) { |
|
|
if (!imported) { |
|
|
console.warn('Unable to import', assetOrPath, imported) |
|
|
console.warn('Unable to import', assetOrPath, imported) |
|
|
return [] |
|
|
return [] |
|
|
} |
|
|
} |
|
|
return this.loadImported<(T|undefined)[]>(imported, options) |
|
|
|
|
|
|
|
|
return this.loadImported<(T | undefined)[]>(imported, options) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// materials: IMaterial[] = [] |
|
|
// materials: IMaterial[] = [] |
|
|
// textures: ITexture[] = [] |
|
|
// textures: ITexture[] = [] |
|
|
|
|
|
|
|
|
// todo move this function to viewer |
|
|
// todo move this function to viewer |
|
|
async loadImported<T extends ValOrArr<ImportResult|undefined> = ImportResult>(imported: T, {autoSetEnvironment = true, autoSetBackground = false, ...options}: AddAssetOptions = {}): Promise<T | never[]> { |
|
|
|
|
|
const arr: (ImportResult|undefined)[] = Array.isArray(imported) ? imported : [imported] |
|
|
|
|
|
|
|
|
async loadImported<T extends ValOrArr<ImportResult | undefined> = ImportResult>(imported: T, { |
|
|
|
|
|
autoSetEnvironment = true, |
|
|
|
|
|
autoSetBackground = false, |
|
|
|
|
|
...options |
|
|
|
|
|
}: AddAssetOptions = {}): Promise<T | never[]> { |
|
|
|
|
|
const arr: (ImportResult | undefined)[] = Array.isArray(imported) ? imported : [imported] |
|
|
let ret: T = Array.isArray(imported) ? [] : undefined as any |
|
|
let ret: T = Array.isArray(imported) ? [] : undefined as any |
|
|
|
|
|
|
|
|
for (const obj of arr) { |
|
|
for (const obj of arr) { |
|
|
|
|
|
|
|
|
case 'model': |
|
|
case 'model': |
|
|
case 'light': |
|
|
case 'light': |
|
|
case 'camera': |
|
|
case 'camera': |
|
|
r = await this.viewer.addSceneObject(<IObject3D|RootSceneImportResult>obj, options) // todo update references in scene update event |
|
|
|
|
|
|
|
|
r = await this.viewer.addSceneObject(<IObject3D | RootSceneImportResult>obj, options) // todo update references in scene update event |
|
|
break |
|
|
break |
|
|
case 'config': |
|
|
case 'config': |
|
|
if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj) |
|
|
if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// legacy |
|
|
// legacy |
|
|
if (obj.type && typeof obj.type === 'string' && (Array.isArray((obj as any).plugins) || |
|
|
if (obj.type && typeof obj.type === 'string' && (Array.isArray((obj as any).plugins) || |
|
|
(obj as any).type === 'ThreeViewer' || this.viewer.getPlugin((obj as any).type))) { |
|
|
|
|
|
|
|
|
(obj as any).type === 'ThreeViewer' || this.viewer.getPlugin((obj as any).type))) { |
|
|
await this.viewer.importConfig(<ISerializedConfig>obj) |
|
|
await this.viewer.importConfig(<ISerializedConfig>obj) |
|
|
} |
|
|
} |
|
|
break |
|
|
break |
|
|
} |
|
|
} |
|
|
this.dispatchEvent({type: 'loadAsset', data: obj}) |
|
|
|
|
|
|
|
|
this.dispatchEvent({type: 'loadAsset', data: obj}) |
|
|
if (Array.isArray(ret)) ret.push(r) |
|
|
if (Array.isArray(ret)) ret.push(r) |
|
|
else ret = r as T |
|
|
else ret = r as T |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
* @param imported |
|
|
* @param imported |
|
|
* @param options |
|
|
* @param options |
|
|
*/ |
|
|
*/ |
|
|
async addProcessedAssets<T extends ImportResult|undefined = ImportResult>(imported: (T|undefined)[], options?: AddAssetOptions): Promise<(T | undefined)[]> { |
|
|
|
|
|
|
|
|
async addProcessedAssets<T extends ImportResult | undefined = ImportResult>(imported: (T | undefined)[], options?: AddAssetOptions): Promise<(T | undefined)[]> { |
|
|
return this.loadImported(imported, options) |
|
|
return this.loadImported(imported, options) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async addAssetSingle<T extends ImportResult = ImportResult>(asset?: string | IAsset | File, options?: ImportAssetOptions): Promise<T|undefined> { |
|
|
|
|
|
|
|
|
async addAssetSingle<T extends ImportResult = ImportResult>(asset?: string | IAsset | File, options?: ImportAssetOptions): Promise<T | undefined> { |
|
|
return !asset ? undefined : (await this.addAsset<T>(asset, options))?.[0] |
|
|
return !asset ? undefined : (await this.addAsset<T>(asset, options))?.[0] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// processAndAddObjects |
|
|
// processAndAddObjects |
|
|
async addRaw<T extends (ImportResult|undefined) = ImportResult>(res: T|T[], options: AddRawOptions = {}): Promise<(T|undefined)[]> { |
|
|
|
|
|
|
|
|
async addRaw<T extends (ImportResult | undefined) = ImportResult>(res: T | T[], options: AddRawOptions = {}): Promise<(T | undefined)[]> { |
|
|
const r = await this.importer.processRaw<T>(res, options) |
|
|
const r = await this.importer.processRaw<T>(res, options) |
|
|
return this.loadImported<T[]>(r, options) |
|
|
return this.loadImported<T[]>(r, options) |
|
|
} |
|
|
} |
|
|
async addRawSingle<T extends ImportResult|undefined = ImportResult|undefined>(res: T, options: AddRawOptions = {}): Promise<T|undefined> { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async addRawSingle<T extends ImportResult | undefined = ImportResult | undefined>(res: T, options: AddRawOptions = {}): Promise<T | undefined> { |
|
|
return (await this.addRaw<T>(res, options))?.[0] |
|
|
return (await this.addRaw<T>(res, options))?.[0] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (data.metadata?.type !== 'Material') { |
|
|
if (data.metadata?.type !== 'Material') { |
|
|
console.warn('Invalid material data', data) |
|
|
console.warn('Invalid material data', data) |
|
|
} |
|
|
} |
|
|
JSONMaterialLoader.DeserializeMaterialJSON(data, this.viewer, meta, event.material).then(()=>{ |
|
|
|
|
|
|
|
|
JSONMaterialLoader.DeserializeMaterialJSON(data, this.viewer, meta, event.material).then(() => { |
|
|
// |
|
|
// |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
dispose() { |
|
|
dispose() { |
|
|
this.importer.dispose() |
|
|
this.importer.dispose() |
|
|
this.materials.dispose() |
|
|
this.materials.dispose() |
|
|
|
|
|
this.processState.clear() |
|
|
this.viewer.scene.removeEventListener('addSceneObject', this._sceneUpdated) |
|
|
this.viewer.scene.removeEventListener('addSceneObject', this._sceneUpdated) |
|
|
this.viewer.scene.removeEventListener('materialChanged', this._sceneUpdated) |
|
|
this.viewer.scene.removeEventListener('materialChanged', this._sceneUpdated) |
|
|
this.exporter.dispose() |
|
|
this.exporter.dispose() |
|
|
|
|
|
|
|
|
], false), // todo: use ImageBitmapLoader if supported (better performance) |
|
|
], false), // todo: use ImageBitmapLoader if supported (better performance) |
|
|
|
|
|
|
|
|
new Importer<JSONMaterialLoader>(JSONMaterialLoader, |
|
|
new Importer<JSONMaterialLoader>(JSONMaterialLoader, |
|
|
['mat', ...this.materials.templates.map(t=>t.typeSlug!).filter(v=>v)], // todo add others |
|
|
|
|
|
[], false, (loader)=>{ |
|
|
|
|
|
|
|
|
['mat', ...this.materials.templates.map(t => t.typeSlug!).filter(v => v)], // todo add others |
|
|
|
|
|
[], false, (loader) => { |
|
|
if (loader) loader.viewer = this.viewer |
|
|
if (loader) loader.viewer = this.viewer |
|
|
return loader |
|
|
return loader |
|
|
}), |
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected _addExporters() { |
|
|
protected _addExporters() { |
|
|
const exporters: IExporter[] = [ |
|
|
const exporters: IExporter[] = [ |
|
|
{ext: ['gltf', 'glb'], extensions: [], ctor: (_, exporter)=>{ |
|
|
|
|
|
const ex = new GLTFExporter2() |
|
|
|
|
|
// This should be added at the end. |
|
|
|
|
|
ex.setup(this.viewer, exporter.extensions) |
|
|
|
|
|
return ex |
|
|
|
|
|
}}, |
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
ext: ['gltf', 'glb'], extensions: [], ctor: (_, exporter) => { |
|
|
|
|
|
const ex = new GLTFExporter2() |
|
|
|
|
|
// This should be added at the end. |
|
|
|
|
|
ex.setup(this.viewer, exporter.extensions) |
|
|
|
|
|
return ex |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
] |
|
|
] |
|
|
|
|
|
|
|
|
this.exporter.addExporter(...exporters) |
|
|
this.exporter.addExporter(...exporters) |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected _setupObjectProcess() { |
|
|
|
|
|
this.importer.addEventListener('processRaw', (event) => { |
|
|
|
|
|
// console.log('preprocess mat', mat) |
|
|
|
|
|
const mat = event.data as IMaterial |
|
|
|
|
|
if (!mat || !mat.isMaterial || !mat.uuid) return |
|
|
|
|
|
if (this.materials?.findMaterial(mat.uuid)) { |
|
|
|
|
|
console.warn('imported material uuid already exists, creating new uuid') |
|
|
|
|
|
mat.uuid = generateUUID() |
|
|
|
|
|
if (mat.userData.uuid) mat.userData.uuid = mat.uuid |
|
|
|
|
|
} |
|
|
|
|
|
// todo: check for name exists also |
|
|
|
|
|
this.materials.registerMaterial(mat) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
this.importer.addEventListener('processRawStart', (event) => { |
|
|
|
|
|
// console.log('preprocess mat', mat) |
|
|
|
|
|
const res = event.data! |
|
|
|
|
|
const options = event.options! as ProcessRawOptions |
|
|
|
|
|
// if (!res.assetType) { |
|
|
|
|
|
// if (res.isBufferGeometry) { // for eg stl todo |
|
|
|
|
|
// res = new Mesh(res, new MeshStandardMaterial()) |
|
|
|
|
|
// } |
|
|
|
|
|
// if (res.isObject3D) { |
|
|
|
|
|
// } |
|
|
|
|
|
// } |
|
|
|
|
|
if (res.isObject3D) { |
|
|
|
|
|
const cameras: Camera[] = [] |
|
|
|
|
|
const lights: Light[] = [] |
|
|
|
|
|
res.traverse((obj: any) => { |
|
|
|
|
|
if (obj.material) { |
|
|
|
|
|
const materials = Array.isArray(obj.material) ? obj.material : [obj.material] |
|
|
|
|
|
const newMaterials = [] |
|
|
|
|
|
for (const material of materials) { |
|
|
|
|
|
const mat = this.materials.convertToIMaterial(material, {createFromTemplate: options.replaceMaterials !== false}) || material |
|
|
|
|
|
mat.uuid = material.uuid |
|
|
|
|
|
mat.userData.uuid = material.uuid |
|
|
|
|
|
newMaterials.push(mat) |
|
|
|
|
|
} |
|
|
|
|
|
if (Array.isArray(obj.material)) obj.material = newMaterials |
|
|
|
|
|
else obj.material = newMaterials[0] |
|
|
|
|
|
} |
|
|
|
|
|
if (obj.isCamera) cameras.push(obj) |
|
|
|
|
|
if (obj.isLight) lights.push(obj) |
|
|
|
|
|
}) |
|
|
|
|
|
for (const camera of cameras) { |
|
|
|
|
|
if ((camera as PerspectiveCamera2).assetType === 'camera') continue |
|
|
|
|
|
// todo: OrthographicCamera |
|
|
|
|
|
if (!(camera as PerspectiveCamera).isPerspectiveCamera || !camera.parent || options.replaceCameras === false) { |
|
|
|
|
|
iCameraCommons.upgradeCamera.call(camera) |
|
|
|
|
|
} else { |
|
|
|
|
|
const newCamera: ICamera = (camera as any).iCamera ?? |
|
|
|
|
|
new PerspectiveCamera2('', this.viewer.canvas) |
|
|
|
|
|
if (camera === newCamera) continue |
|
|
|
|
|
camera.parent.children.splice(camera.parent.children.indexOf(camera), 1, newCamera) |
|
|
|
|
|
newCamera.parent = camera.parent as any |
|
|
|
|
|
newCamera.copy(camera as any) |
|
|
|
|
|
camera.parent = null |
|
|
|
|
|
;(newCamera as any).uuid = camera.uuid |
|
|
|
|
|
newCamera.userData.uuid = camera.uuid |
|
|
|
|
|
;(camera as any).iCamera = newCamera |
|
|
|
|
|
// console.log('replacing camera', camera, newCamera) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (const light of lights) { |
|
|
|
|
|
if ((light as ILight).assetType === 'light') continue |
|
|
|
|
|
if (!light.parent || options.replaceLights === false) { |
|
|
|
|
|
iLightCommons.upgradeLight.call(light) |
|
|
|
|
|
} else { |
|
|
|
|
|
const newLight: ILight | undefined = (light as any).iLight ?? |
|
|
|
|
|
(light as any).isDirectionalLight ? new DirectionalLight2() : |
|
|
|
|
|
(light as any).isPointLight ? new PointLight2() : |
|
|
|
|
|
(light as any).isSpotLight ? new SpotLight2() : |
|
|
|
|
|
(light as any).isAmbientLight ? new AmbientLight2() : |
|
|
|
|
|
(light as any).isHemisphereLight ? new HemisphereLight2() : |
|
|
|
|
|
(light as any).isRectAreaLight ? new RectAreaLight2() : |
|
|
|
|
|
undefined |
|
|
|
|
|
if (light === newLight || !newLight) continue |
|
|
|
|
|
light.parent.children.splice(light.parent.children.indexOf(light), 1, newLight) |
|
|
|
|
|
newLight.parent = light.parent as any |
|
|
|
|
|
newLight.copy(light as any) |
|
|
|
|
|
light.parent = null |
|
|
|
|
|
;(newLight as any).uuid = light.uuid |
|
|
|
|
|
newLight.userData.uuid = light.uuid |
|
|
|
|
|
;(light as any).iLight = newLight |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
iObjectCommons.upgradeObject3D.call(res) |
|
|
|
|
|
} else if (res.isMaterial) { |
|
|
|
|
|
iMaterialCommons.upgradeMaterial.call(res) |
|
|
|
|
|
// todo update res by generating new material? |
|
|
|
|
|
} else if (res.isTexture) { |
|
|
|
|
|
upgradeTexture.call(res) |
|
|
|
|
|
|
|
|
|
|
|
if (event?.options?.generateMipmaps !== undefined) |
|
|
|
|
|
res.generateMipmaps = event?.options.generateMipmaps |
|
|
|
|
|
if (!res.generateMipmaps && !res.isRenderTargetTexture) { // todo: do we need to check more? |
|
|
|
|
|
res.minFilter = res.minFilter === LinearMipmapLinearFilter ? LinearFilter : res.minFilter |
|
|
|
|
|
res.magFilter = res.magFilter === LinearMipmapLinearFilter ? LinearFilter : res.magFilter |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
// todo other asset/object types? |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* State of download/upload/process/other processes in the viewer. |
|
|
|
|
|
* Subscribes to importer and exporter by default, more can be added by plugins like {@link FileTransferPlugin} |
|
|
|
|
|
*/ |
|
|
|
|
|
processState: Map<string, {state: string, progress: number | undefined}> = new Map() |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Set process state for a path |
|
|
|
|
|
* Progress should be a number between 0 and 100 |
|
|
|
|
|
* Pass undefined in value to remove the state |
|
|
|
|
|
* @param path |
|
|
|
|
|
* @param value |
|
|
|
|
|
*/ |
|
|
|
|
|
setProcessState(path: string, value: {state: string, progress: number | undefined} | undefined) { |
|
|
|
|
|
if (value === undefined) this.processState.delete(path) |
|
|
|
|
|
else this.processState.set(path, value) |
|
|
|
|
|
this.dispatchEvent({type: 'processStateUpdate'}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected _setupProcessState() { |
|
|
|
|
|
this.importer.addEventListener('importFile', (data: any) => { |
|
|
|
|
|
this.setProcessState(data.path, data.state !== 'done' ? { |
|
|
|
|
|
state: data.state, |
|
|
|
|
|
progress: data.progress ? data.progress * 100 : undefined, |
|
|
|
|
|
} : undefined) |
|
|
|
|
|
}) |
|
|
|
|
|
this.importer.addEventListener('processRawStart', (data: any) => { |
|
|
|
|
|
this.setProcessState(data.path, { |
|
|
|
|
|
state: 'processing', |
|
|
|
|
|
progress: undefined, |
|
|
|
|
|
}) |
|
|
|
|
|
}) |
|
|
|
|
|
this.importer.addEventListener('processRaw', (data: any) => { |
|
|
|
|
|
this.setProcessState(data.path, undefined) |
|
|
|
|
|
}) |
|
|
|
|
|
this.exporter.addEventListener('exportFile', (data: any) => { |
|
|
|
|
|
this.setProcessState(data.obj.name, data.state !== 'done' ? { |
|
|
|
|
|
state: data.state, |
|
|
|
|
|
progress: data.progress ? data.progress * 100 : undefined, |
|
|
|
|
|
} : undefined) |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// region deprecated |
|
|
// region deprecated |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
|
|
|
|
|
|
* @param res |
|
|
* @param res |
|
|
* @param options |
|
|
* @param options |
|
|
*/ |
|
|
*/ |
|
|
async addImported<T extends (ImportResult|undefined) = ImportResult>(res: T|T[], options: AddRawOptions = {}): Promise<(T|undefined)[]> { |
|
|
|
|
|
|
|
|
async addImported<T extends (ImportResult | undefined) = ImportResult>(res: T | T[], options: AddRawOptions = {}): Promise<(T | undefined)[]> { |
|
|
console.error('addImported is deprecated, use addRaw instead') |
|
|
console.error('addImported is deprecated, use addRaw instead') |
|
|
return this.addRaw(res, options) |
|
|
return this.addRaw(res, options) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
static readonly PluginType = 'AssetManager' |
|
|
static readonly PluginType = 'AssetManager' |
|
|
// endregion |
|
|
// endregion |
|
|
|
|
|
|
|
|
} |
|
|
} |