Settings.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { Parameters } from './Parameters.js';
  2. import { WebGPURenderer, WebGLBackend, Node } from 'three/webgpu';
  3. import { getItem, setItem } from '../Inspector.js';
  4. const _EXTENSIONS_PATH = '../extensions/extensions.json';
  5. const _init = WebGPURenderer.prototype.init;
  6. function forceWebGL( enable ) {
  7. if ( enable ) {
  8. WebGPURenderer.prototype.init = async function () {
  9. if ( this.backend.isWebGLBackend !== true ) {
  10. const parameters = this.backend.parameters;
  11. this.backend = new WebGLBackend( parameters );
  12. }
  13. return _init.call( this );
  14. };
  15. } else {
  16. WebGPURenderer.prototype.init = _init;
  17. }
  18. }
  19. let _state = null;
  20. function _loadState() {
  21. if ( _state !== null ) return _state;
  22. const settings = getItem( 'settings' );
  23. _state = {
  24. forceWebGL: settings.forceWebGL !== undefined ? settings.forceWebGL : false,
  25. captureStackTrace: settings.captureStackTrace !== undefined ? settings.captureStackTrace : false,
  26. activeExtensions: settings.activeExtensions !== undefined ? settings.activeExtensions : {}
  27. };
  28. if ( _state.forceWebGL ) {
  29. forceWebGL( true );
  30. }
  31. if ( _state.captureStackTrace ) {
  32. Node.captureStackTrace = true;
  33. }
  34. return _state;
  35. }
  36. function _saveState() {
  37. setItem( 'settings', {
  38. forceWebGL: _state.forceWebGL,
  39. captureStackTrace: _state.captureStackTrace,
  40. activeExtensions: _state.activeExtensions
  41. } );
  42. }
  43. _loadState();
  44. //
  45. class Settings extends Parameters {
  46. constructor() {
  47. super( { name: 'Settings' } );
  48. this.extensions = {};
  49. const currentState = _loadState();
  50. // UI
  51. const rendererGroup = this.createGroup( 'Renderer' );
  52. rendererGroup.add( currentState, 'forceWebGL' ).name( 'Force WebGL' ).onChange( ( enable ) => {
  53. forceWebGL( enable );
  54. _saveState();
  55. location.reload();
  56. } );
  57. rendererGroup.add( currentState, 'captureStackTrace' ).name( 'Capture Stack Trace' ).onChange( ( enable ) => {
  58. Node.captureStackTrace = enable;
  59. _saveState();
  60. location.reload();
  61. } );
  62. }
  63. init() {
  64. const extensionsGroup = this.createGroup( 'Extensions' );
  65. this._getExtensions().then( extensions => {
  66. for ( const extension of extensions ) {
  67. extension.active = false;
  68. extension.loaded = false;
  69. extension.tab = null;
  70. this.extensions[ extension.name ] = extension;
  71. extension.ui = extensionsGroup.add( { [ extension.name ]: false }, extension.name ).onChange( async ( value ) => {
  72. this.setActiveExtension( extension.name, value );
  73. // User preference
  74. if ( value ) {
  75. _state.activeExtensions[ extension.name ] = {
  76. name: extension.name,
  77. url: extension.url
  78. };
  79. } else {
  80. delete _state.activeExtensions[ extension.name ];
  81. }
  82. //
  83. this._updateExtensionUI( extension );
  84. _saveState();
  85. } );
  86. // Set user-defined state
  87. if ( _state.activeExtensions[ extension.name ] !== undefined ) {
  88. extension.ui.setValue( true );
  89. }
  90. }
  91. } );
  92. }
  93. async setActiveExtension( name, value ) {
  94. const extension = this.extensions[ name ];
  95. const inspector = this.inspector;
  96. if ( extension ) {
  97. if ( value ) {
  98. await this._loadExtension( inspector, extension );
  99. } else {
  100. await this._unloadExtension( inspector, extension );
  101. }
  102. }
  103. }
  104. _updateExtensionUI( extension ) {
  105. const forceActive = extension.active && _state.activeExtensions[ extension.name ] === undefined;
  106. if ( forceActive ) {
  107. extension.ui.checkbox.checked = true;
  108. extension.ui.domElement.style.setProperty( '--accent-color', 'var(--color-green)' );
  109. } else {
  110. extension.ui.domElement.style.removeProperty( '--accent-color' );
  111. }
  112. }
  113. async _unloadExtension( inspector, extension ) {
  114. if ( extension.active === false ) return;
  115. //
  116. inspector.removeTab( extension.tab );
  117. extension.active = false;
  118. extension.loaded = false;
  119. extension.tab = null;
  120. this._updateExtensionUI( extension );
  121. this.dispatchEvent( { type: 'extensionremoved', name: extension.name } );
  122. }
  123. async _loadExtension( inspector, extension ) {
  124. if ( extension.active === true ) return;
  125. //
  126. extension.active = true;
  127. const extUrl = new URL( extension.url, new URL( _EXTENSIONS_PATH, import.meta.url ) ).href;
  128. const module = await import( extUrl );
  129. const keys = Object.keys( module );
  130. const ExtensionClass = module[ keys[ 0 ] ];
  131. const extensionTab = new ExtensionClass();
  132. inspector.addTab( extensionTab );
  133. extension.loaded = true;
  134. extension.tab = extensionTab;
  135. this._updateExtensionUI( extension );
  136. this.dispatchEvent( { type: 'extensionadded', name: extension.name, tab: extensionTab } );
  137. }
  138. async _getExtensions() {
  139. const url = new URL( _EXTENSIONS_PATH, import.meta.url );
  140. const extensions = await fetch( url ).then( res => res.json() );
  141. return extensions;
  142. }
  143. }
  144. export { Settings };
粤ICP备19079148号