| </ul> | </ul> | ||||
| <h2 class="category">Samples</h2> | <h2 class="category">Samples</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="html-js-sample/">HTML/JS Sample </a></li> | |||||
| <li><a href="react-js-sample/">React/JS Sample </a></li> | |||||
| <li><a href="react-jsx-sample/">React/JSX Sample </a></li> | |||||
| <li><a href="react-tsx-sample/">React/TSX Sample </a></li> | |||||
| <li><a href="vue-html-sample/">Vue/HTML Sample </a></li> | |||||
| <li><a href="vue-sfc-sample/">Vue/SFC Sample </a></li> | |||||
| <li><a href="svelte-sample/">Svelte Sample </a></li> | |||||
| <li><a href="./html-js-sample/">HTML/JS Sample </a></li> | |||||
| <li><a href="./react-js-sample/">React/JS Sample </a></li> | |||||
| <li><a href="./react-jsx-sample/">React/JSX Sample </a></li> | |||||
| <li><a href="./react-tsx-sample/">React/TSX Sample </a></li> | |||||
| <li><a href="./vue-html-sample/">Vue/HTML Sample </a></li> | |||||
| <li><a href="./vue-sfc-sample/">Vue/SFC Sample </a></li> | |||||
| <li><a href="./svelte-sample/">Svelte Sample </a></li> | |||||
| </ul> | </ul> | ||||
| <h2 class="category">Lights</h2> | <h2 class="category">Lights</h2> | ||||
| <ul> | <ul> |
| {ctor: ()=>new SimpleJSONExporter(), ext: ['json']}, | {ctor: ()=>new SimpleJSONExporter(), ext: ['json']}, | ||||
| {ctor: ()=>new SimpleTextExporter(), ext: ['txt', 'text']}, | {ctor: ()=>new SimpleTextExporter(), ext: ['txt', 'text']}, | ||||
| {ctor: ()=>new EXRExporter2(), ext: ['exr']}, | {ctor: ()=>new EXRExporter2(), ext: ['exr']}, | ||||
| // {ctor: ()=>new EXRExporter2(), ext: ['png', 'jpeg', 'webp']}, // todo | |||||
| // {ctor: ()=>new GLTFDracoExporter(), ext: ['gltf', 'glb']}, | // {ctor: ()=>new GLTFDracoExporter(), ext: ['gltf', 'glb']}, | ||||
| ] | ] | ||||
| import {AViewerPluginSync, ISerializedConfig, ThreeViewer} from '../../viewer' | import {AViewerPluginSync, ISerializedConfig, ThreeViewer} from '../../viewer' | ||||
| import {onChange, serialize, wrapThisFunction} from 'ts-browser-helpers' | import {onChange, serialize, wrapThisFunction} from 'ts-browser-helpers' | ||||
| import {SerializationMetaType} from '../../utils' | import {SerializationMetaType} from '../../utils' | ||||
| import {uiConfig, uiToggle} from 'uiconfig.js' | |||||
| import {uiToggle} from 'uiconfig.js' | |||||
| export abstract class PipelinePassPlugin<T extends IPipelinePass, TPassId extends IPassID, TEvent extends string, TViewer extends ThreeViewer=ThreeViewer> extends AViewerPluginSync<TEvent, TViewer> { | export abstract class PipelinePassPlugin<T extends IPipelinePass, TPassId extends IPassID, TEvent extends string, TViewer extends ThreeViewer=ThreeViewer> extends AViewerPluginSync<TEvent, TViewer> { | ||||
| abstract passId: TPassId | abstract passId: TPassId | ||||
| @onChange(PipelinePassPlugin.prototype.setDirty) | @onChange(PipelinePassPlugin.prototype.setDirty) | ||||
| enabled = true | enabled = true | ||||
| @uiConfig() | |||||
| // @uiConfig() | |||||
| @serialize('pass') | @serialize('pass') | ||||
| protected _pass?: T | protected _pass?: T | ||||
| protected abstract _createPass():T | protected abstract _createPass():T |
| } | } | ||||
| } | } | ||||
| @uiButton('Toggle FullScreen') | @uiButton('Toggle FullScreen') | ||||
| async toggle(elem: HTMLElement): Promise<void> { | |||||
| async toggle(element?: HTMLElement): Promise<void> { | |||||
| if (this.isFullScreen()) { | if (this.isFullScreen()) { | ||||
| return this.exit() | return this.exit() | ||||
| } else { | } else { | ||||
| return this.enter(elem) | |||||
| return this.enter(element) | |||||
| } | } | ||||
| } | } | ||||
| setDirty() { | setDirty() { | ||||
| if (!this._viewer) return | if (!this._viewer) return | ||||
| if (this.isDisabled()) this.setSelectedObject(undefined) // todo | |||||
| if (this.isDisabled()) this.setSelectedObject(undefined) | |||||
| this._viewer.setDirty() | this._viewer.setDirty() | ||||
| } | } | ||||
| constructor(selection: Class<SelectionWidget>|undefined = BoxSelectionWidget, pickUi = true, autoFocus = false) { | constructor(selection: Class<SelectionWidget>|undefined = BoxSelectionWidget, pickUi = true, autoFocus = false) { | ||||
| return this._picker?.selectedObject as T || undefined | return this._picker?.selectedObject as T || undefined | ||||
| } | } | ||||
| setSelectedObject(object: IObject3D|undefined, focusCamera = false) { // todo: listen to object dispose | |||||
| if (this.isDisabled()) return | |||||
| setSelectedObject(object: IObject3D|undefined, focusCamera = false) { // todo: listen to object disposed | |||||
| const disabled = this.isDisabled() | |||||
| if (disabled && !object) return | |||||
| if (!this._picker) return | if (!this._picker) return | ||||
| const t = this.autoFocus | const t = this.autoFocus | ||||
| this.autoFocus = false | this.autoFocus = false | ||||
| this._picker.selectedObject = object || null | this._picker.selectedObject = object || null | ||||
| this.autoFocus = t | this.autoFocus = t | ||||
| if (t || focusCamera) this.focusObject(object) | |||||
| if (!disabled && object && (t || focusCamera)) this.focusObject(object) | |||||
| } | } | ||||
| onAdded(viewer: ThreeViewer): void { | onAdded(viewer: ThreeViewer): void { | ||||
| this.focusObject(selected) | this.focusObject(selected) | ||||
| } | } | ||||
| } | } | ||||
| private _hoverObjectChanged = (e: any) => { | private _hoverObjectChanged = (e: any) => { |
| * It uses WEBGI_materials_clearcoat_tint glTF extension to save the settings in glTF files. | * It uses WEBGI_materials_clearcoat_tint glTF extension to save the settings in glTF files. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| @uiFolderContainer('ClearcoatTint Materials') | |||||
| @uiFolderContainer('Clearcoat Tint (MatExt)') | |||||
| export class ClearcoatTintPlugin extends AViewerPluginSync<''> { | export class ClearcoatTintPlugin extends AViewerPluginSync<''> { | ||||
| static readonly PluginType = 'ClearcoatTintPlugin' | static readonly PluginType = 'ClearcoatTintPlugin' | ||||
| * It uses WEBGI_materials_custom_bump_map glTF extension to save the settings in glTF files. | * It uses WEBGI_materials_custom_bump_map glTF extension to save the settings in glTF files. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| @uiFolderContainer('CustomBumpMap Materials') | |||||
| @uiFolderContainer('Custom BumpMap (MatExt)') | |||||
| export class CustomBumpMapPlugin extends AViewerPluginSync<''> { | export class CustomBumpMapPlugin extends AViewerPluginSync<''> { | ||||
| static readonly PluginType = 'CustomBumpMapPlugin' | static readonly PluginType = 'CustomBumpMapPlugin' | ||||
| * It uses WEBGI_materials_fragment_clipping_extension glTF extension to save the settings in glTF files. | * It uses WEBGI_materials_fragment_clipping_extension glTF extension to save the settings in glTF files. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| @uiFolderContainer('FragmentClipping Materials') | |||||
| @uiFolderContainer('Fragment Clipping (MatExt)') | |||||
| export class FragmentClippingExtensionPlugin extends AViewerPluginSync<''> { | export class FragmentClippingExtensionPlugin extends AViewerPluginSync<''> { | ||||
| static readonly PluginType = 'FragmentClippingExtensionPlugin1' | static readonly PluginType = 'FragmentClippingExtensionPlugin1' | ||||
| * It uses WEBGI_materials_noise_bump glTF extension to save the settings in glTF files. | * It uses WEBGI_materials_noise_bump glTF extension to save the settings in glTF files. | ||||
| * @category Plugins | * @category Plugins | ||||
| */ | */ | ||||
| @uiFolderContainer('NoiseBump Materials') | |||||
| @uiFolderContainer('Noise/Sparkle Bump (MatExt)') | |||||
| export class NoiseBumpMaterialPlugin extends AViewerPluginSync<''> { | export class NoiseBumpMaterialPlugin extends AViewerPluginSync<''> { | ||||
| static readonly PluginType = 'NoiseBumpMaterialPlugin' | static readonly PluginType = 'NoiseBumpMaterialPlugin' | ||||
| private readonly _renderSize = new Vector2(512, 512) // this is updated automatically. | private readonly _renderSize = new Vector2(512, 512) // this is updated automatically. | ||||
| protected readonly _renderer: IWebGLRenderer<this> | protected readonly _renderer: IWebGLRenderer<this> | ||||
| private _renderScale = 1. | private _renderScale = 1. | ||||
| @uiSlider('Render Scale', [0.1, 8], 0.05) // keep here in code so its at the top in the UI | |||||
| get renderScale(): number { | |||||
| return this._renderScale | |||||
| } | |||||
| set renderScale(value: number) { | |||||
| if (value !== this._renderScale) { | |||||
| this._renderScale = value | |||||
| this.setSize(undefined, undefined, true) | |||||
| } | |||||
| } | |||||
| @uiConfig(undefined, {label: 'Passes'}) | @uiConfig(undefined, {label: 'Passes'}) | ||||
| private _passes: IPipelinePass[] = [] | private _passes: IPipelinePass[] = [] | ||||
| private _pipeline: IPassID[] = [] | private _pipeline: IPassID[] = [] | ||||
| get renderSize(): Vector2 { | get renderSize(): Vector2 { | ||||
| return this._renderSize | return this._renderSize | ||||
| } | } | ||||
| @uiSlider('Render Scale', [0.1, 8], 0.05) | |||||
| get renderScale(): number { | |||||
| return this._renderScale | |||||
| } | |||||
| set renderScale(value: number) { | |||||
| if (value !== this._renderScale) { | |||||
| this._renderScale = value | |||||
| this.setSize(undefined, undefined, true) | |||||
| } | |||||
| } | |||||
| get context(): WebGLRenderingContext { | get context(): WebGLRenderingContext { | ||||
| return this._context | return this._context |
| throw 'Not a temp target' | throw 'Not a temp target' | ||||
| } | } | ||||
| if (this._releasedTempTargets[key].length > this.maxTempPerKey) { | if (this._releasedTempTargets[key].length > this.maxTempPerKey) { | ||||
| this.removeTrackedTarget(target) | |||||
| target.dispose() | target.dispose() | ||||
| this._trackedTempTargets.splice(this._trackedTempTargets.indexOf(target), 1) | |||||
| } else this._releasedTempTargets[key].push(target) | } else this._releasedTempTargets[key].push(target) | ||||
| } | } | ||||
| RootSceneImportResult, | RootSceneImportResult, | ||||
| } from '../assetmanager' | } from '../assetmanager' | ||||
| import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin' | import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin' | ||||
| import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | |||||
| import {uiConfig, UiObjectConfig, uiPanelContainer} from 'uiconfig.js' | |||||
| import {IRenderTarget} from '../rendering' | import {IRenderTarget} from '../rendering' | ||||
| import type {CameraViewPlugin, ProgressivePlugin} from '../plugins' | import type {CameraViewPlugin, ProgressivePlugin} from '../plugins' | ||||
| // noinspection ES6PreferShortImport | // noinspection ES6PreferShortImport | ||||
| * The ThreeViewer is the main class in the framework to manage a scene, render and add plugins to it. | * The ThreeViewer is the main class in the framework to manage a scene, render and add plugins to it. | ||||
| * @category Viewer | * @category Viewer | ||||
| */ | */ | ||||
| @uiFolderContainer('Viewer') | |||||
| @uiPanelContainer('Viewer') | |||||
| export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes> { | export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes> { | ||||
| public static readonly VERSION = VERSION | public static readonly VERSION = VERSION | ||||
| public static readonly ConfigTypeSlug = 'vjson' | public static readonly ConfigTypeSlug = 'vjson' |