| } from '@gltf-transform/core' | } from '@gltf-transform/core' | ||||
| import {EncoderOptions} from '@gltf-transform/extensions/dist/khr-draco-mesh-compression/encoder' | import {EncoderOptions} from '@gltf-transform/extensions/dist/khr-draco-mesh-compression/encoder' | ||||
| import {ALL_EXTENSIONS, KHRDracoMeshCompression} from '@gltf-transform/extensions' | import {ALL_EXTENSIONS, KHRDracoMeshCompression} from '@gltf-transform/extensions' | ||||
| import {DRACOLoader2, GLTFExporter2, GLTFExporter2Options, GLTFViewerConfigExtension, IExportParser} from 'threepipe' | |||||
| import {DRACOLoader2, GLTFExporter2, GLTFExporter2Options, GLTFViewerConfigExtension, IExportWriter} from 'threepipe' | |||||
| /** | /** | ||||
| * GLTF Draco Exporter | * GLTF Draco Exporter | ||||
| * | * | ||||
| * Extension of GLTFExporter2 that runs the output through gltf-transform for draco compression. | * Extension of GLTFExporter2 that runs the output through gltf-transform for draco compression. | ||||
| */ | */ | ||||
| export class GLTFDracoExporter extends GLTFExporter2 implements IExportParser { | |||||
| export class GLTFDracoExporter extends GLTFExporter2 implements IExportWriter { | |||||
| public loader?: DRACOLoader2 // required for loading draco libs. | public loader?: DRACOLoader2 // required for loading draco libs. | ||||
| private _io: WebIO | private _io: WebIO | ||||
| private _loadedLibs = false | private _loadedLibs = false |
| import {EventDispatcher, WebGLRenderTarget} from 'three' | import {EventDispatcher, WebGLRenderTarget} from 'three' | ||||
| import {IMaterial, IObject3D, ITexture} from '../core' | import {IMaterial, IObject3D, ITexture} from '../core' | ||||
| import {BlobExt, ExportFileOptions, IAssetExporter, IExporter, IExportParser} from './IExporter' | |||||
| import {BlobExt, ExportFileOptions, IAssetExporter, IExporter, IExportWriter} from './IExporter' | |||||
| import {EXRExporter2, SimpleJSONExporter, SimpleTextExporter} from './export' | import {EXRExporter2, SimpleJSONExporter, SimpleTextExporter} from './export' | ||||
| import {IRenderTarget} from '../rendering' | import {IRenderTarget} from '../rendering' | ||||
| export interface AssetExporterEventMap { | export interface AssetExporterEventMap { | ||||
| exporterCreate: {exporter: IExporter, parser: IExportParser} | |||||
| exporterCreate: {exporter: IExporter, parser: IExportWriter} // todo rename parser to writer | |||||
| exportFile: { | exportFile: { | ||||
| obj: IObject3D|IMaterial|ITexture|IRenderTarget, | obj: IObject3D|IMaterial|ITexture|IRenderTarget, | ||||
| state: 'processing'|'exporting'|'done'|'error', | state: 'processing'|'exporting'|'done'|'error', | ||||
| } | } | ||||
| if (processed.blob) res = processed.blob | if (processed.blob) res = processed.blob | ||||
| else { | else { | ||||
| const parser = this._getParser(ext) | |||||
| const parser = this._getWriter(ext) | |||||
| this.dispatchEvent({type: 'exportFile', obj, state:'exporting', exportOptions: options}) | this.dispatchEvent({type: 'exportFile', obj, state:'exporting', exportOptions: options}) | ||||
| res = await parser.parseAsync(processed.obj, {exportExt: processed.ext ?? ext, ...options}) as BlobExt | res = await parser.parseAsync(processed.obj, {exportExt: processed.ext ?? ext, ...options}) as BlobExt | ||||
| return res | return res | ||||
| } | } | ||||
| private _createParser(ext: string): IExportParser { | |||||
| private _createParser(ext: string): IExportWriter { | |||||
| const exporter = this.exporters.find(e => e.ext.includes(ext)) | const exporter = this.exporters.find(e => e.ext.includes(ext)) | ||||
| if (!exporter) | if (!exporter) | ||||
| throw new Error(`No exporter found for extension ${ext}`) | throw new Error(`No exporter found for extension ${ext}`) | ||||
| const parser = exporter?.ctor(this, exporter) | const parser = exporter?.ctor(this, exporter) | ||||
| if (!parser) throw new Error(`Unable to create parser for extension ${ext}`) | if (!parser) throw new Error(`Unable to create parser for extension ${ext}`) | ||||
| this._cachedParsers.push({ext: exporter.ext, parser}) | |||||
| this._cachedWriters.push({ext: exporter.ext, parser}) | |||||
| this.dispatchEvent({type: 'exporterCreate', exporter, parser}) | this.dispatchEvent({type: 'exporterCreate', exporter, parser}) | ||||
| return parser | return parser | ||||
| } | } | ||||
| private _cachedParsers: {parser: IExportParser, ext: string[]}[] = [] | |||||
| private _getParser(ext: string): IExportParser { | |||||
| return this._cachedParsers.find(e => e.ext.includes(ext))?.parser ?? this._createParser(ext) | |||||
| private _cachedWriters: {parser: IExportWriter, ext: string[]}[] = [] | |||||
| private _getWriter(ext: string): IExportWriter { | |||||
| return this._cachedWriters.find(e => e.ext.includes(ext))?.parser ?? this._createParser(ext) | |||||
| } | } | ||||
| public async processBeforeExport(obj: IObject3D|IMaterial|ITexture|IRenderTarget, options: ExportFileOptions = {}): Promise<{obj:any, ext:string, typeExt?:string, blob?: BlobExt}|undefined> { | public async processBeforeExport(obj: IObject3D|IMaterial|ITexture|IRenderTarget, options: ExportFileOptions = {}): Promise<{obj:any, ext:string, typeExt?:string, blob?: BlobExt}|undefined> { |
| export type BlobExt = Blob&{ext:string} | export type BlobExt = Blob&{ext:string} | ||||
| export interface IExportParser { | |||||
| export interface IExportWriter { | |||||
| // parse(obj: any, options: AnyOptions): any; | // parse(obj: any, options: AnyOptions): any; | ||||
| parseAsync(obj: any, options: AnyOptions): Promise<Blob> | parseAsync(obj: any, options: AnyOptions): Promise<Blob> | ||||
| } | } | ||||
| export interface IExporter { | export interface IExporter { | ||||
| extensions?: any[] | extensions?: any[] | ||||
| ext: string[]; | ext: string[]; | ||||
| ctor: (assetExporter: IAssetExporter, exporter: IExporter)=>IExportParser|undefined; | |||||
| ctor: (assetExporter: IAssetExporter, exporter: IExporter)=>IExportWriter|undefined; | |||||
| } | } | ||||
| export type ExportFileOptions = { | export type ExportFileOptions = { |
| import {DataTexture, WebGLRenderTarget} from 'three' | import {DataTexture, WebGLRenderTarget} from 'three' | ||||
| import {EXRExporter, EXRExporterParseOptions} from 'three/examples/jsm/exporters/EXRExporter.js' | import {EXRExporter, EXRExporterParseOptions} from 'three/examples/jsm/exporters/EXRExporter.js' | ||||
| import {IExportParser} from '../IExporter' | |||||
| import {IExportWriter} from '../IExporter' | |||||
| import {IRenderTarget} from '../../rendering' | import {IRenderTarget} from '../../rendering' | ||||
| export class EXRExporter2 extends EXRExporter implements IExportParser { | |||||
| export class EXRExporter2 extends EXRExporter implements IExportWriter { | |||||
| async parseAsync(obj: IRenderTarget|DataTexture, options: EXRExporterParseOptions): Promise<Blob> { | async parseAsync(obj: IRenderTarget|DataTexture, options: EXRExporterParseOptions): Promise<Blob> { | ||||
| const target = <IRenderTarget>obj | const target = <IRenderTarget>obj | ||||
| if (target.isWebGLRenderTarget && !target.renderManager) throw new Error('No renderManager on renderTarget') | if (target.isWebGLRenderTarget && !target.renderManager) throw new Error('No renderManager on renderTarget') |
| import {GLTFExporter, GLTFExporterPlugin} from 'three/examples/jsm/exporters/GLTFExporter.js' | import {GLTFExporter, GLTFExporterPlugin} from 'three/examples/jsm/exporters/GLTFExporter.js' | ||||
| import {IExportParser} from '../IExporter' | |||||
| import {IExportWriter} from '../IExporter' | |||||
| import {GLTFWriter2} from './GLTFWriter2' | import {GLTFWriter2} from './GLTFWriter2' | ||||
| import {AnimationClip, Object3D} from 'three' | import {AnimationClip, Object3D} from 'three' | ||||
| import {ThreeViewer} from '../../viewer' | import {ThreeViewer} from '../../viewer' | ||||
| [key: string]: any | [key: string]: any | ||||
| } | } | ||||
| export class GLTFExporter2 extends GLTFExporter implements IExportParser { | |||||
| export class GLTFExporter2 extends GLTFExporter implements IExportWriter { | |||||
| constructor() { | constructor() { | ||||
| super() | super() |
| import {IExportParser} from '../IExporter' | |||||
| import {IExportWriter} from '../IExporter' | |||||
| export class SimpleJSONExporter implements IExportParser { | |||||
| export class SimpleJSONExporter implements IExportWriter { | |||||
| async parseAsync(obj: any, {jsonSpaces = 2}): Promise<Blob> { | async parseAsync(obj: any, {jsonSpaces = 2}): Promise<Blob> { | ||||
| return new Blob([JSON.stringify(obj, null, jsonSpaces)], {type: 'application/json'}) | return new Blob([JSON.stringify(obj, null, jsonSpaces)], {type: 'application/json'}) | ||||
| } | } |
| import {IExportParser} from '../IExporter' | |||||
| import {IExportWriter} from '../IExporter' | |||||
| import {AnyOptions} from 'ts-browser-helpers' | import {AnyOptions} from 'ts-browser-helpers' | ||||
| export class SimpleTextExporter implements IExportParser { | |||||
| export class SimpleTextExporter implements IExportWriter { | |||||
| async parseAsync(obj: any, _: AnyOptions): Promise<Blob> { | async parseAsync(obj: any, _: AnyOptions): Promise<Blob> { | ||||
| return new Blob([obj], {type: 'text/plain'}) | return new Blob([obj], {type: 'text/plain'}) | ||||
| } | } |
| export type {AssetManagerOptions, AddRawOptions, ImportAddOptions, AddAssetOptions} from './AssetManager' | export type {AssetManagerOptions, AddRawOptions, ImportAddOptions, AddAssetOptions} from './AssetManager' | ||||
| export type {IAsset, IFile, IAssetID, IAssetList} from './IAsset' | export type {IAsset, IFile, IAssetID, IAssetList} from './IAsset' | ||||
| export type {ImportResult, IImportResultUserData, ImportResultObject, IAssetImporter, IAssetImporterEventMap, ImportAssetOptions, ImportFilesOptions, LoadFileOptions, ProcessRawOptions, RootSceneImportResult, ImportResultExtras} from './IAssetImporter' | export type {ImportResult, IImportResultUserData, ImportResultObject, IAssetImporter, IAssetImporterEventMap, ImportAssetOptions, ImportFilesOptions, LoadFileOptions, ProcessRawOptions, RootSceneImportResult, ImportResultExtras} from './IAssetImporter' | ||||
| export type {IAssetExporter, IExporter, IExportParser, ExportFileOptions, BlobExt} from './IExporter' | |||||
| export type {IAssetExporter, IExporter, IExportWriter, ExportFileOptions, BlobExt} from './IExporter' | |||||
| export type {IImporter, ILoader} from './IImporter' | export type {IImporter, ILoader} from './IImporter' | ||||
| export * from './import/index' | export * from './import/index' |