| @@ -117,6 +117,7 @@ To make changes and run the example, click on the CodePen button on the top righ | |||
| - [KTXLoadPlugin](#ktxloadplugin) - Add support for loading .ktx files | |||
| - [Packages](#threepipe-packages) | |||
| - [@threepipe/plugin-tweakpane](#threepipeplugin-tweakpane) Tweakpane UI Plugin | |||
| - [@threepipe/plugin-blueprintjs](#threepipeplugin-blueprintjs) BlueprintJs UI Plugin | |||
| - [@threepipe/plugin-tweakpane-editor](#threepipeplugin-tweakpane-editor) - Tweakpane Editor Plugin | |||
| - [@threepipe/plugin-extra-importers](#threepipeplugin-extra-importers) - Plugin for loading more file types supported by loaders in three.js | |||
| - [@threepipe/plugin-blend-importer](#threepipeplugin-blend-importer) - Blender to add support for loading .blend file | |||
| @@ -830,7 +831,7 @@ In some classes, the ui configs are also generated using typescript decorators. | |||
| The `uiConfig` is also added to all three.js objects and materials when they are added to the scene. | |||
| The UIs can be generated at runtime using any of the UI plugins like [TweakpaneUIPlugin](#threepipeplugin-tweakpane). | |||
| The UIs can be generated at runtime using any of the UI plugins like [TweakpaneUIPlugin](#threepipeplugin-tweakpane), [BlueprintJsUiPlugin](#threepipeplugin-blueprintjs) | |||
| An example showing how to create a UI for a material | |||
| @@ -1101,7 +1102,7 @@ Notes: | |||
| * `plugin.toJSON()` and `plugin.fromJSON()` or `ThreeSerialization` can be used to serialize and deserialize plugins. `viewer.exportPluginConfig` and `viewer.importPluginConfig` also exist for this. | |||
| * @serialize('label') decorator can be used to mark any public/private variable as serializable. label (optional) corresponds to the key in JSON. | |||
| * @serialize supports instances of ITexture, IMaterial, all primitive types, simple JS objects, three.js math classes(Vector2, Vector3, Matrix3...), and some more. | |||
| * uiDecorators can be used to mark properties and functions that will be shown in the Ui. The Ui shows up automatically when TweakpaneUiPlugin is added to the viewer. Plugins have special features in the UI for download preset and saving state. | |||
| * uiDecorators can be used to mark properties and functions that will be shown in the Ui. The Ui shows up automatically when TweakpaneUiPlugin/BlueprintJsUiPlugin is added to the viewer. Plugins have special features in the UI for download preset and saving state. | |||
| Check various plugins in the source code for more examples. | |||
| @@ -2918,11 +2919,11 @@ Additional plugins can be found in the [plugins](plugins/) directory. | |||
| These add support for integrating with other libraries, adding new features, and other functionality with different licenses. | |||
| ## @threepipe/plugin-tweakpane | |||
| Tewakpane UI plugin for ThreePipe | |||
| [Tweakpane](https://tweakpane.github.io/docs/) UI plugin for ThreePipe | |||
| [//]: # (todo: image) | |||
| Example: https://threepipe.org/examples/#viewer-uiconfig/ | |||
| Example: https://threepipe.org/examples/#tweakpane-ui-plugin/ | |||
| Source Code: [plugins/tweakpane/src/TweakpaneUiPlugin.ts](plugins/tweakpane/src/TweakpaneUiPlugin.ts) | |||
| @@ -2933,7 +2934,7 @@ NPM: `npm install @threepipe/plugin-tweakpane` | |||
| CDN: https://threepipe.org/plugins/tweakpane/dist/index.mjs | |||
| TweakpaneUiPlugin adds support for using [uiconfig-tweakpane](https://github.com/repalash/uiconfig-tweakpane) | |||
| to create a configuration UI in applications using the [Tweakpane](https://cocopon.github.io/tweakpane/) library. | |||
| to create a configuration UI in applications using the [Tweakpane](https://tweakpane.github.io/docs/) library. | |||
| The plugin takes the [uiconfig](https://github.com/repalash/uiconfig.js) | |||
| that's defined in the viewer and all the objects to automatically render a UI in the browser. | |||
| @@ -2953,6 +2954,42 @@ plugin.appendChild(viewer.uiConfig) | |||
| plugin.setupPlugins(TonemapPlugin, DropzonePlugin) | |||
| ``` | |||
| ## @threepipe/plugin-blueprintjs | |||
| [Blueprint.js](https://blueprintjs.com/) UI plugin for ThreePipe | |||
| [//]: # (todo: image) | |||
| Example: https://threepipe.org/examples/#blueprintjs-ui-plugin/ | |||
| Source Code: [plugins/blueprintjs/src/BlueprintJsUiPlugin.ts](plugins/blueprintjs/src/BlueprintJsUiPlugin.ts) | |||
| API Reference: [BlueprintJsUiPlugin](https://threepipe.org/plugins/blueprintjs/docs/classes/BlueprintJsUiPlugin.html) | |||
| NPM: `npm install @threepipe/plugin-blueprintjs` | |||
| CDN: https://threepipe.org/plugins/blueprintjs/dist/index.mjs | |||
| BlueprintJsUiPlugin adds support for using [uiconfig-blueprint](https://github.com/repalash/uiconfig-blueprint) | |||
| to create a configuration UI in applications using the [BlueprintJs](https://blueprintjs.com/) library. | |||
| The plugin takes the [uiconfig](https://github.com/repalash/uiconfig.js) | |||
| that's defined in the viewer and all the objects to automatically render a UI in the browser. | |||
| ```typescript | |||
| import {IObject3D, ThreeViewer, TonemapPlugin} from 'threepipe' | |||
| import {BlueprintJsUiPlugin} from '@threepipe/plugin-blueprintjs' | |||
| const viewer = new ThreeViewer({...}) | |||
| // Add the plugin | |||
| const plugin = viewer.addPluginSync(new BlueprintJsUiPlugin(true)) // true to show expanded the UI by default | |||
| // Add the UI for the viewer | |||
| plugin.appendChild(viewer.uiConfig) | |||
| // Add UI for some plugins | |||
| plugin.setupPlugins(TonemapPlugin, DropzonePlugin) | |||
| ``` | |||
| ## @threepipe/plugin-tweakpane-editor | |||
| Tweakpane Editor Plugin for ThreePipe | |||
| @@ -0,0 +1,36 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>BlueprintJs Ui Plugin</title> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <!-- Import maps polyfill --> | |||
| <!-- Remove this when import maps will be widely supported --> | |||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||
| <script type="importmap"> | |||
| { | |||
| "imports": { | |||
| "threepipe": "./../../dist/index.mjs", | |||
| "@threepipe/plugin-blueprintjs": "./../../plugins/blueprintjs/dist/index.mjs" | |||
| } | |||
| } | |||
| </script> | |||
| <style id="example-style"> | |||
| html, body, #canvas-container, #mcanvas { | |||
| width: 100%; | |||
| height: 100%; | |||
| margin: 0; | |||
| overflow: hidden; | |||
| } | |||
| </style> | |||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||
| </head> | |||
| <body> | |||
| <div id="canvas-container"> | |||
| <canvas id="mcanvas"></canvas> | |||
| </div> | |||
| </body> | |||
| @@ -0,0 +1,25 @@ | |||
| import {_testFinish, IObject3D, ThreeViewer, TonemapPlugin} from 'threepipe' | |||
| import {BlueprintJsUiPlugin} from '@threepipe/plugin-blueprintjs' | |||
| async function init() { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| }) | |||
| const ui = viewer.addPluginSync(new BlueprintJsUiPlugin()) | |||
| ui.appendChild(viewer.uiConfig) | |||
| ui.setupPluginUi(TonemapPlugin) | |||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||
| const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||
| autoCenter: true, | |||
| autoScale: true, | |||
| }) | |||
| const mesh = result?.getObjectByName('node_damagedHelmet_-6514') | |||
| ui.appendChild(mesh?.uiConfig) | |||
| } | |||
| init().then(_testFinish) | |||
| @@ -274,6 +274,11 @@ | |||
| <li><a href="./scene-uiconfig/">Scene UI </a></li> | |||
| <li><a href="./viewer-uiconfig/">Viewer UI </a></li> | |||
| </ul> | |||
| <h2 class="category">UI Plugins</h2> | |||
| <ul> | |||
| <li><a href="./tweakpane-ui-plugin/">Tweakpane UI Plugin </a></li> | |||
| <li><a href="./blueprintjs-ui-plugin/">Blueprint.js UI Plugin </a></li> | |||
| </ul> | |||
| <h2 class="category">Animation</h2> | |||
| <ul> | |||
| <li><a href="./gltf-animation-plugin/">glTF Animation Plugin </a></li> | |||
| @@ -300,7 +305,13 @@ | |||
| </ul> | |||
| <h2 class="category">Samples</h2> | |||
| <ul> | |||
| <li><a href="./html-sample/">HTML/JS 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> | |||
| <h2 class="category">Lights</h2> | |||
| <ul> | |||
| @@ -28,16 +28,16 @@ async function init() { | |||
| autoScale: true, | |||
| }) | |||
| const ground = new Mesh( | |||
| const plane = new Mesh( | |||
| new PlaneGeometry(5, 5) | |||
| .translate(0, 0, -4), | |||
| new PhysicalMaterial({ | |||
| color: '#ffffff', | |||
| }) | |||
| ) | |||
| ground.castShadow = false | |||
| ground.receiveShadow = true | |||
| viewer.scene.addObject(ground) | |||
| plane.castShadow = false | |||
| plane.receiveShadow = true | |||
| viewer.scene.addObject(plane) | |||
| const camera = new PerspectiveCamera2('', viewer.canvas, false, 45, 1) | |||
| camera.position.set(0, 0, 5) | |||
| @@ -47,7 +47,7 @@ async function init() { | |||
| camera.far = 10 | |||
| camera.setDirty() | |||
| const vCam = virtualCameras.addCamera(camera) | |||
| ground.material.map = vCam.target.texture as Texture | |||
| plane.material.map = vCam.target.texture as Texture | |||
| popmotion.animate({ | |||
| from: 0, | |||
| @@ -0,0 +1,131 @@ | |||
| { | |||
| "name": "@threepipe/plugin-blueprintjs", | |||
| "version": "0.1.0", | |||
| "lockfileVersion": 2, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-blueprintjs", | |||
| "version": "0.1.0", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| }, | |||
| "devDependencies": { | |||
| "uiconfig-blueprint": "file:./../../../uiconfig-blueprint" | |||
| } | |||
| }, | |||
| "../../../uiconfig-blueprint": { | |||
| "version": "0.0.3", | |||
| "dev": true, | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "@types/react": "^18.0.28", | |||
| "@types/react-dom": "^18.0.11", | |||
| "@types/three": "^0.152.1", | |||
| "@types/webxr": "^0.5.10", | |||
| "react": "^18.2.0", | |||
| "react-dom": "^18.2.0", | |||
| "uiconfig.js": "^0.0.8" | |||
| }, | |||
| "devDependencies": { | |||
| "@blueprintjs/core": "^5.7.2", | |||
| "@blueprintjs/icons": "^5.5.0", | |||
| "@blueprintjs/select": "^5.0.20", | |||
| "@rollup/plugin-commonjs": "^24.0.1", | |||
| "@rollup/plugin-json": "^6.0.0", | |||
| "@rollup/plugin-node-resolve": "^15.0.1", | |||
| "@rollup/plugin-replace": "^5.0.2", | |||
| "@rollup/plugin-terser": "^0.4.0", | |||
| "@rollup/plugin-typescript": "^11.0.0", | |||
| "@types/react": "^18.0.28", | |||
| "@types/react-dom": "^18.0.11", | |||
| "@types/uuid": "^9.0.1", | |||
| "@vitejs/plugin-react": "^4.2.1", | |||
| "autoprefixer": "^10.4.13", | |||
| "blueprint-styler": "^5.0.2", | |||
| "clean-package": "^2.2.0", | |||
| "local-web-server": "^5.3.0", | |||
| "postcss": "^8.4.32", | |||
| "react": "^18.2.0", | |||
| "react-colorful": "^5.6.1", | |||
| "react-dom": "^18.2.0", | |||
| "rimraf": "^5.0.1", | |||
| "rollup": "^3.17.2", | |||
| "rollup-plugin-delete": "^2.0.0", | |||
| "rollup-plugin-license": "^3.0.1", | |||
| "rollup-plugin-multi-input": "^1.3.3", | |||
| "rollup-plugin-postcss": "^4.0.2", | |||
| "sass": "^1.69.5", | |||
| "ts-browser-helpers": "^0.8.0", | |||
| "tslib": "^2.5.0", | |||
| "typedoc": "^0.23.26", | |||
| "typescript": "^4.9.5", | |||
| "uuid": "^9.0.0", | |||
| "vite": "^5.0.10", | |||
| "vite-plugin-dts": "^3.6.4" | |||
| }, | |||
| "optionalDependencies": { | |||
| "win-node-env": "^0.6.1" | |||
| } | |||
| }, | |||
| "../../src": {}, | |||
| "node_modules/threepipe": { | |||
| "resolved": "../../src", | |||
| "link": true | |||
| }, | |||
| "node_modules/uiconfig-blueprint": { | |||
| "resolved": "../../../uiconfig-blueprint", | |||
| "link": true | |||
| } | |||
| }, | |||
| "dependencies": { | |||
| "threepipe": { | |||
| "version": "file:../../src" | |||
| }, | |||
| "uiconfig-blueprint": { | |||
| "version": "file:../../../uiconfig-blueprint", | |||
| "requires": { | |||
| "@blueprintjs/core": "^5.7.2", | |||
| "@blueprintjs/icons": "^5.5.0", | |||
| "@blueprintjs/select": "^5.0.20", | |||
| "@rollup/plugin-commonjs": "^24.0.1", | |||
| "@rollup/plugin-json": "^6.0.0", | |||
| "@rollup/plugin-node-resolve": "^15.0.1", | |||
| "@rollup/plugin-replace": "^5.0.2", | |||
| "@rollup/plugin-terser": "^0.4.0", | |||
| "@rollup/plugin-typescript": "^11.0.0", | |||
| "@types/react": "^18.0.28", | |||
| "@types/react-dom": "^18.0.11", | |||
| "@types/three": "^0.152.1", | |||
| "@types/uuid": "^9.0.1", | |||
| "@types/webxr": "^0.5.10", | |||
| "@vitejs/plugin-react": "^4.2.1", | |||
| "autoprefixer": "^10.4.13", | |||
| "blueprint-styler": "^5.0.2", | |||
| "clean-package": "^2.2.0", | |||
| "local-web-server": "^5.3.0", | |||
| "postcss": "^8.4.32", | |||
| "react": "^18.2.0", | |||
| "react-colorful": "^5.6.1", | |||
| "react-dom": "^18.2.0", | |||
| "rimraf": "^5.0.1", | |||
| "rollup": "^3.17.2", | |||
| "rollup-plugin-delete": "^2.0.0", | |||
| "rollup-plugin-license": "^3.0.1", | |||
| "rollup-plugin-multi-input": "^1.3.3", | |||
| "rollup-plugin-postcss": "^4.0.2", | |||
| "sass": "^1.69.5", | |||
| "ts-browser-helpers": "^0.8.0", | |||
| "tslib": "^2.5.0", | |||
| "typedoc": "^0.23.26", | |||
| "typescript": "^4.9.5", | |||
| "uiconfig.js": "^0.0.8", | |||
| "uuid": "^9.0.0", | |||
| "vite": "^5.0.10", | |||
| "vite-plugin-dts": "^3.6.4", | |||
| "win-node-env": "^0.6.1" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| { | |||
| "name": "@threepipe/plugin-blueprintjs", | |||
| "description": "Blueprint.js UI Plugin for ThreePipe", | |||
| "version": "0.1.0", | |||
| "devDependencies": { | |||
| "uiconfig-blueprint": "^0.0.3" | |||
| }, | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| }, | |||
| "type": "module", | |||
| "main": "dist/index.js", | |||
| "module": "dist/index.mjs", | |||
| "types": "dist/index.d.ts", | |||
| "source": "src/index.ts", | |||
| "files": [ | |||
| "dist", | |||
| "src" | |||
| ], | |||
| "scripts": { | |||
| "new:pack": "npm run prepare && clean-package && npm pack && clean-package restore", | |||
| "new:publish": "npm run prepare && clean-package && npm publish --access public && clean-package restore", | |||
| "prepare": "npm run build", | |||
| "build": "rimraf dist && NODE_ENV=production rollup -c", | |||
| "dev": "rollup -c -w", | |||
| "docs": "rimraf docs && npx typedoc" | |||
| }, | |||
| "author": "repalash <palash@shaders.app>", | |||
| "license": "Apache-2.0", | |||
| "keywords": [ | |||
| "three", | |||
| "three.js", | |||
| "blueprint", | |||
| "threepipe", | |||
| "plugin" | |||
| ], | |||
| "bugs": { | |||
| "url": "https://github.com/repalash/threepipe/issues" | |||
| }, | |||
| "homepage": "https://github.com/repalash/threepipe#readme", | |||
| "repository": { | |||
| "type": "git", | |||
| "url": "git://github.com/repalash/threepipe.git" | |||
| }, | |||
| "clean-package": { | |||
| "remove": [ | |||
| "clean-package", | |||
| "scripts", | |||
| "devDependencies", | |||
| "//", | |||
| "markdown-to-html" | |||
| ], | |||
| "replace": { | |||
| "dependencies": { | |||
| "threepipe": "^0.0.18" | |||
| } | |||
| } | |||
| }, | |||
| "//": { | |||
| "dependencies": { | |||
| "uiconfig-blueprint": "^0.0.3" | |||
| }, | |||
| "local_dependencies": { | |||
| "uiconfig-blueprint": "^file:./../uiconfig-blueprint" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,102 @@ | |||
| // rollup.config.js | |||
| import commonjs from '@rollup/plugin-commonjs'; | |||
| import json from '@rollup/plugin-json'; | |||
| import resolve from '@rollup/plugin-node-resolve'; | |||
| import typescript from '@rollup/plugin-typescript'; | |||
| import license from 'rollup-plugin-license' | |||
| import packageJson from './package.json' assert {type: 'json'}; | |||
| import path from 'path' | |||
| import {fileURLToPath} from 'url'; | |||
| import terser from "@rollup/plugin-terser"; | |||
| import postcss from 'rollup-plugin-postcss' | |||
| import replace from '@rollup/plugin-replace' | |||
| const __filename = fileURLToPath(import.meta.url); | |||
| const __dirname = path.dirname(__filename); | |||
| const {name, version, author} = packageJson | |||
| // const {main, module, browser} = packageJson["clean-package"].replace | |||
| const isProduction = process.env.NODE_ENV === 'production' | |||
| const settings = { | |||
| globals: { | |||
| "three": "threepipe", | |||
| "threepipe": "threepipe" | |||
| }, | |||
| sourcemap: true | |||
| } | |||
| export default { | |||
| input: './src/index.ts', | |||
| output: [ | |||
| // { | |||
| // file: main, | |||
| // name: main, | |||
| // ...settings, | |||
| // format: 'cjs', | |||
| // plugins: [ | |||
| // isProduction && terser() | |||
| // ] | |||
| // }, | |||
| { | |||
| file: './dist/index.mjs', | |||
| ...settings, | |||
| name: name, | |||
| format: 'es', | |||
| inlineDynamicImports: true, | |||
| plugins: [ | |||
| isProduction && terser() | |||
| ] | |||
| }, | |||
| { | |||
| file: './dist/index.js', | |||
| ...settings, | |||
| name: name, | |||
| format: 'umd', | |||
| inlineDynamicImports: true, | |||
| plugins: [ | |||
| isProduction && terser() | |||
| ] | |||
| } | |||
| ], | |||
| external: Object.keys(settings.globals), | |||
| plugins: [ | |||
| replace({ | |||
| 'from \'three\'': 'from \'threepipe\'', | |||
| delimiters: ['', ''], | |||
| }), | |||
| replace({ | |||
| 'process.env.NODE_ENV': JSON.stringify('production'), | |||
| }), | |||
| postcss({ | |||
| modules: false, | |||
| autoModules: true, // todo; issues with typescript import css, because inject is false | |||
| inject: false, | |||
| minimize: isProduction, | |||
| // Or with custom options for `postcss-modules` | |||
| }), | |||
| json(), | |||
| resolve({}), | |||
| typescript({ | |||
| tsconfig: './tsconfig.json', | |||
| }), | |||
| commonjs({ | |||
| include: 'node_modules/**', | |||
| extensions: ['.js'], | |||
| ignoreGlobal: false, | |||
| sourceMap: false | |||
| }), | |||
| license({ | |||
| banner: ` | |||
| @license | |||
| ${name} v${version} | |||
| Copyright 2022<%= moment().format('YYYY') > 2022 ? '-' + moment().format('YYYY') : null %> ${author} | |||
| ${packageJson.license} License | |||
| `, | |||
| thirdParty: { | |||
| output: path.join(__dirname, 'dist', 'dependencies.txt'), | |||
| includePrivate: true, // Default is false. | |||
| }, | |||
| }) | |||
| ] | |||
| } | |||
| @@ -0,0 +1,151 @@ | |||
| import {UiConfigRendererBlueprint} from 'uiconfig-blueprint' | |||
| import { | |||
| Class, | |||
| Color, | |||
| createDiv, | |||
| CustomContextMenu, | |||
| downloadBlob, | |||
| getOrCall, | |||
| IEvent, | |||
| IViewerPlugin, | |||
| IViewerPluginSync, | |||
| Texture, | |||
| ThreeViewer, | |||
| uploadFile, | |||
| Vector2, | |||
| Vector3, | |||
| Vector4, | |||
| } from 'threepipe' | |||
| import {UiObjectConfig} from 'uiconfig.js' | |||
| export class BlueprintJsUiPlugin extends UiConfigRendererBlueprint implements IViewerPluginSync { | |||
| declare ['constructor']: typeof BlueprintJsUiPlugin | |||
| static readonly PluginType = 'BlueprintJsUi' | |||
| enabled = true | |||
| constructor(container: HTMLElement = document.body) { | |||
| super(container, { | |||
| autoPostFrame: false, | |||
| }) | |||
| this.THREE = {Color, Vector4, Vector3, Vector2, Texture} as any | |||
| } | |||
| protected _viewer?: ThreeViewer | |||
| onAdded(viewer: ThreeViewer): void { | |||
| this._viewer = viewer | |||
| viewer.addEventListener('preRender', this._preRender) | |||
| viewer.addEventListener('postRender', this._postRender) | |||
| viewer.addEventListener('preFrame', this._preFrame) | |||
| viewer.addEventListener('postFrame', this._postFrame) | |||
| } | |||
| onRemove(viewer: ThreeViewer): void { | |||
| this._viewer = undefined | |||
| viewer.removeEventListener('preRender', this._preRender) | |||
| viewer.removeEventListener('postRender', this._postRender) | |||
| viewer.removeEventListener('preFrame', this._preFrame) | |||
| viewer.removeEventListener('postFrame', this._postFrame) | |||
| this.dispose() | |||
| } | |||
| private _plugins: IViewerPlugin[] = [] | |||
| setupPlugins(...plugins: Class<IViewerPlugin>[]): void { | |||
| plugins.forEach(plugin => this.setupPluginUi(plugin)) | |||
| } | |||
| setupPluginUi<T extends IViewerPlugin>(plugin: T|Class<T>): UiObjectConfig | undefined { | |||
| const p = (<Class<IViewerPlugin>>plugin).prototype ? this._viewer?.getPlugin<T>(<Class<T>>plugin) : <T>plugin | |||
| if (!p) { | |||
| console.warn('plugin not found:', plugin) | |||
| return undefined | |||
| } | |||
| this._plugins.push(p) | |||
| if (p.uiConfig && p.uiConfig.hidden === undefined) p.uiConfig.hidden = false // todo; this is a hack for now | |||
| const ui = p.uiConfig | |||
| this.appendChild(ui) | |||
| // this._setupPluginSerializationContext(ui, p) | |||
| return ui | |||
| } | |||
| // @ts-expect-error todo: port to blueprint from tweakpane | |||
| private _setupPluginSerializationContext(ui: any, p: IViewerPlugin) { | |||
| // serialization | |||
| if (!(ui?.uiRef && p.toJSON)) return; | |||
| (p as any)._defaultState = typeof p.toJSON === 'function' ? p.toJSON() : null | |||
| ;(p as any).resetDefaults = async() => { | |||
| if (!(p as any)._defaultState) return | |||
| await p.fromJSON?.((p as any)._defaultState) | |||
| ui.uiRefresh?.(true, 'postFrame') | |||
| } | |||
| const topBtn = (ui.uiRef as any).controller_.view.element | |||
| const opBtn = createDiv({ | |||
| innerHTML: '⋮', | |||
| classList: ['pluginOptionsButton'], | |||
| elementTag: 'button', | |||
| }) | |||
| opBtn.onclick = (ev) => { | |||
| const ops = {} as any | |||
| if (typeof p.toJSON === 'function') { | |||
| ops['download preset'] = async() => { | |||
| if (!this._viewer) return | |||
| const json = this._viewer.exportPluginConfig(p) | |||
| await downloadBlob(new Blob([JSON.stringify(json, null, 2)], {type: 'application/json'}), 'preset.' + (p.constructor as any).PluginType + '.json') | |||
| } | |||
| } | |||
| if (typeof p.fromJSON === 'function') { | |||
| ops['upload preset'] = async() => { | |||
| const files = await uploadFile(false, false) | |||
| if (files.length === 0) return | |||
| const file = files[0] | |||
| const text = await file.text() | |||
| const json = JSON.parse(text) | |||
| await this._viewer?.importPluginConfig(json, p) | |||
| ui.uiRefresh?.(true, 'postFrame') | |||
| } | |||
| if ((p as any)._defaultState) ops['reset defaults'] = () => (p as any).resetDefaults?.() | |||
| } | |||
| const menu = CustomContextMenu.Create(ops, topBtn.clientWidth - 120, 12) | |||
| topBtn.append(menu) | |||
| ev.preventDefault() | |||
| } | |||
| topBtn.appendChild(opBtn) | |||
| } | |||
| refreshPluginsEnabled() { | |||
| this._plugins.forEach(p=>{ | |||
| const config = p.uiConfig | |||
| if (config) { | |||
| // const enabled = (p as any).enabled ?? true | |||
| // safeSetProperty(config, 'hidden', !enabled, true) | |||
| // if (config.expanded) | |||
| // safeSetProperty(config, 'expanded', config.expanded && enabled, true) | |||
| if (getOrCall(config.hidden) !== true) | |||
| config.uiRefresh?.(true, 'postFrame') | |||
| else if (config.uiRef) { | |||
| config.uiRef.hidden = true | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * Required for loading files in BPFileComponent | |||
| */ | |||
| get fileLoader() { | |||
| return this._viewer | |||
| } | |||
| private _preRender = () => this.refreshQueue('preRender') | |||
| private _postRender = () => this.refreshQueue('postRender') | |||
| private _postFrame = (e: IEvent<'postFrame'>) => { | |||
| this.dispatchEvent(e) | |||
| this.refreshQueue('postFrame') | |||
| } | |||
| private _preFrame = () => this.refreshQueue('preFrame') | |||
| // alert = async(message?: string): Promise<void> =>this._viewer ? this._viewer.dialog.alert(message) : window?.alert(message) | |||
| // confirm = async(message?: string): Promise<boolean> =>this._viewer ? this._viewer.dialog.confirm(message) : window?.confirm(message) | |||
| // prompt = async(message?: string, _default?: string, cancel = true): Promise<string | null> =>this._viewer ? this._viewer.dialog.prompt(message, _default, cancel) : window?.prompt(message, _default) | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| declare module '*.txt' { | |||
| const content: string | |||
| export default content | |||
| } | |||
| declare module '*.glsl' { | |||
| const content: string | |||
| export default content | |||
| } | |||
| declare module '*.vert' { | |||
| const content: string | |||
| export default content | |||
| } | |||
| declare module '*.frag' { | |||
| const content: string | |||
| export default content | |||
| } | |||
| declare module '*.module.scss' { | |||
| const content: any | |||
| export default content | |||
| export const stylesheet: string | |||
| } | |||
| declare module '*.module.css' { | |||
| const content: any | |||
| export default content | |||
| export const stylesheet: string | |||
| } | |||
| declare module '*.css' { | |||
| const content: string | |||
| export default content | |||
| } | |||
| // export {} | |||
| // hack for typedoc | |||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||
| // declare type OffscreenCanvas = HTMLCanvasElement | |||
| @@ -0,0 +1 @@ | |||
| export {BlueprintJsUiPlugin} from './BlueprintJsUiPlugin' | |||
| @@ -0,0 +1,41 @@ | |||
| { | |||
| "compilerOptions": { | |||
| "baseUrl": "./src", | |||
| "rootDir": "./src", | |||
| "allowJs": false, | |||
| "checkJs": false, | |||
| "skipLibCheck": true, | |||
| "allowSyntheticDefaultImports": true, | |||
| "experimentalDecorators": true, | |||
| "isolatedModules": true, | |||
| "module": "es2020", | |||
| "noImplicitAny": true, | |||
| "declaration": true, | |||
| "declarationMap": true, | |||
| "declarationDir": "dist", | |||
| "outDir": "dist", | |||
| "noImplicitThis": true, | |||
| "noUnusedLocals": true, | |||
| "noUnusedParameters": true, | |||
| "removeComments": false, | |||
| "preserveConstEnums": true, | |||
| "moduleResolution": "node", | |||
| "emitDecoratorMetadata": false, | |||
| "sourceMap": true, | |||
| "target": "ES2020", | |||
| "strictNullChecks": true, | |||
| "lib": [ | |||
| "es2020", | |||
| "esnext", | |||
| "dom" | |||
| ] | |||
| }, | |||
| "include": [ | |||
| "./src/**/*", | |||
| ], | |||
| "exclude": [ | |||
| "node_modules", | |||
| "**/*.spec.ts", | |||
| "dist" | |||
| ] | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| { | |||
| "extends": [ | |||
| "../../typedoc.json" | |||
| ], | |||
| "entryPoints": [ | |||
| "src/index.ts" | |||
| ], | |||
| "name": "Threepipe Blueprint.js Plugin", | |||
| "readme": "none" | |||
| } | |||