Initial project import
This commit is contained in:
238
node_modules/three/examples/jsm/inspector/tabs/Console.js
generated
vendored
Normal file
238
node_modules/three/examples/jsm/inspector/tabs/Console.js
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
import { Tab } from '../ui/Tab.js';
|
||||
|
||||
class Console extends Tab {
|
||||
|
||||
constructor( options = {} ) {
|
||||
|
||||
super( 'Console', options );
|
||||
|
||||
this.filters = { info: true, warn: true, error: true };
|
||||
this.filterText = '';
|
||||
|
||||
this.buildHeader();
|
||||
|
||||
this.logContainer = document.createElement( 'div' );
|
||||
this.logContainer.id = 'console-log';
|
||||
this.content.appendChild( this.logContainer );
|
||||
|
||||
}
|
||||
|
||||
buildHeader() {
|
||||
|
||||
const header = document.createElement( 'div' );
|
||||
header.className = 'console-header';
|
||||
|
||||
const filterInput = document.createElement( 'input' );
|
||||
filterInput.type = 'text';
|
||||
filterInput.className = 'console-filter-input';
|
||||
filterInput.placeholder = 'Filter...';
|
||||
filterInput.addEventListener( 'input', ( e ) => {
|
||||
|
||||
this.filterText = e.target.value.toLowerCase();
|
||||
this.applyFilters();
|
||||
|
||||
} );
|
||||
|
||||
const copyButton = document.createElement( 'button' );
|
||||
copyButton.className = 'console-copy-button';
|
||||
copyButton.title = 'Copy all';
|
||||
copyButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
|
||||
copyButton.addEventListener( 'click', () => this.copyAll( copyButton ) );
|
||||
|
||||
const buttonsGroup = document.createElement( 'div' );
|
||||
buttonsGroup.className = 'console-buttons-group';
|
||||
|
||||
Object.keys( this.filters ).forEach( type => {
|
||||
|
||||
const label = document.createElement( 'label' );
|
||||
label.className = 'custom-checkbox';
|
||||
label.style.color = `var(--${type === 'info' ? 'text-primary' : 'color-' + ( type === 'warn' ? 'yellow' : 'red' )})`;
|
||||
|
||||
const checkbox = document.createElement( 'input' );
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.checked = this.filters[ type ];
|
||||
checkbox.dataset.type = type;
|
||||
|
||||
const checkmark = document.createElement( 'span' );
|
||||
checkmark.className = 'checkmark';
|
||||
|
||||
label.appendChild( checkbox );
|
||||
label.appendChild( checkmark );
|
||||
label.append( type.charAt( 0 ).toUpperCase() + type.slice( 1 ) );
|
||||
buttonsGroup.appendChild( label );
|
||||
|
||||
} );
|
||||
|
||||
buttonsGroup.addEventListener( 'change', ( e ) => {
|
||||
|
||||
const type = e.target.dataset.type;
|
||||
if ( type in this.filters ) {
|
||||
|
||||
this.filters[ type ] = e.target.checked;
|
||||
this.applyFilters();
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
buttonsGroup.appendChild( copyButton );
|
||||
|
||||
header.appendChild( filterInput );
|
||||
header.appendChild( buttonsGroup );
|
||||
this.content.appendChild( header );
|
||||
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
|
||||
const messages = this.logContainer.querySelectorAll( '.log-message' );
|
||||
messages.forEach( msg => {
|
||||
|
||||
const type = msg.dataset.type;
|
||||
const text = msg.dataset.rawText.toLowerCase();
|
||||
|
||||
const showByType = this.filters[ type ];
|
||||
const showByText = text.includes( this.filterText );
|
||||
|
||||
msg.classList.toggle( 'hidden', ! ( showByType && showByText ) );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
copyAll( button ) {
|
||||
|
||||
const win = this.logContainer.ownerDocument.defaultView;
|
||||
const selection = win.getSelection();
|
||||
const selectedText = selection.toString();
|
||||
const textInConsole = selectedText && this.logContainer.contains( selection.anchorNode );
|
||||
|
||||
let text;
|
||||
if ( textInConsole ) {
|
||||
|
||||
text = selectedText;
|
||||
|
||||
} else {
|
||||
|
||||
const messages = this.logContainer.querySelectorAll( '.log-message:not(.hidden)' );
|
||||
text = Array.from( messages ).map( msg => msg.dataset.rawText ).join( '\n' );
|
||||
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText( text );
|
||||
|
||||
button.classList.add( 'copied' );
|
||||
setTimeout( () => button.classList.remove( 'copied' ), 350 );
|
||||
|
||||
}
|
||||
|
||||
_getIcon( type, subType ) {
|
||||
|
||||
let icon;
|
||||
|
||||
if ( subType === 'tip' ) {
|
||||
|
||||
icon = '💭';
|
||||
|
||||
} else if ( subType === 'tsl' ) {
|
||||
|
||||
icon = '✨';
|
||||
|
||||
} else if ( subType === 'webgpurenderer' ) {
|
||||
|
||||
icon = '🎨';
|
||||
|
||||
} else if ( type === 'warn' ) {
|
||||
|
||||
icon = '⚠️';
|
||||
|
||||
} else if ( type === 'error' ) {
|
||||
|
||||
icon = '🔴';
|
||||
|
||||
} else if ( type === 'info' ) {
|
||||
|
||||
icon = 'ℹ️';
|
||||
|
||||
}
|
||||
|
||||
return icon;
|
||||
|
||||
}
|
||||
|
||||
_formatMessage( type, text ) {
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
const prefixMatch = text.match( /^([\w\.]+:\s)/ );
|
||||
let content = text;
|
||||
|
||||
if ( prefixMatch ) {
|
||||
|
||||
const fullPrefix = prefixMatch[ 0 ];
|
||||
const parts = fullPrefix.slice( 0, - 2 ).split( '.' );
|
||||
const shortPrefix = ( parts.length > 1 ? parts[ parts.length - 1 ] : parts[ 0 ] ) + ':';
|
||||
|
||||
const icon = this._getIcon( type, shortPrefix.split( ':' )[ 0 ].toLowerCase() );
|
||||
|
||||
fragment.appendChild( document.createTextNode( icon + ' ' ) );
|
||||
|
||||
const prefixSpan = document.createElement( 'span' );
|
||||
prefixSpan.className = 'log-prefix';
|
||||
prefixSpan.textContent = shortPrefix;
|
||||
fragment.appendChild( prefixSpan );
|
||||
content = text.substring( fullPrefix.length );
|
||||
|
||||
}
|
||||
|
||||
const parts = content.split( /(".*?"|'.*?'|`.*?`)/g ).map( p => p.trim() ).filter( Boolean );
|
||||
|
||||
parts.forEach( ( part, index ) => {
|
||||
|
||||
if ( /^("|'|`)/.test( part ) ) {
|
||||
|
||||
const codeSpan = document.createElement( 'span' );
|
||||
codeSpan.className = 'log-code';
|
||||
codeSpan.textContent = part.slice( 1, - 1 );
|
||||
fragment.appendChild( codeSpan );
|
||||
|
||||
} else {
|
||||
|
||||
if ( index > 0 ) part = ' ' + part; // add space before parts except the first
|
||||
if ( index < parts.length - 1 ) part += ' '; // add space between parts
|
||||
|
||||
fragment.appendChild( document.createTextNode( part ) );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return fragment;
|
||||
|
||||
}
|
||||
|
||||
addMessage( type, text ) {
|
||||
|
||||
const msg = document.createElement( 'div' );
|
||||
msg.className = `log-message ${type}`;
|
||||
msg.dataset.type = type;
|
||||
msg.dataset.rawText = text;
|
||||
|
||||
msg.appendChild( this._formatMessage( type, text ) );
|
||||
|
||||
const showByType = this.filters[ type ];
|
||||
const showByText = text.toLowerCase().includes( this.filterText );
|
||||
msg.classList.toggle( 'hidden', ! ( showByType && showByText ) );
|
||||
|
||||
this.logContainer.appendChild( msg );
|
||||
this.logContainer.scrollTop = this.logContainer.scrollHeight;
|
||||
if ( this.logContainer.children.length > 200 ) {
|
||||
|
||||
this.logContainer.removeChild( this.logContainer.firstChild );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Console };
|
||||
128
node_modules/three/examples/jsm/inspector/tabs/Memory.js
generated
vendored
Normal file
128
node_modules/three/examples/jsm/inspector/tabs/Memory.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Tab } from '../ui/Tab.js';
|
||||
import { List } from '../ui/List.js';
|
||||
import { Graph } from '../ui/Graph.js';
|
||||
import { Item } from '../ui/Item.js';
|
||||
import { createValueSpan, setText, formatBytes } from '../ui/utils.js';
|
||||
|
||||
class Memory extends Tab {
|
||||
|
||||
constructor( options = {} ) {
|
||||
|
||||
super( 'Memory', options );
|
||||
|
||||
const memoryList = new List( 'Name', 'Count', 'Size' );
|
||||
memoryList.setGridStyle( 'minmax(200px, 2fr) 60px 100px' );
|
||||
memoryList.domElement.style.minWidth = '300px';
|
||||
|
||||
const scrollWrapper = document.createElement( 'div' );
|
||||
scrollWrapper.className = 'list-scroll-wrapper';
|
||||
scrollWrapper.appendChild( memoryList.domElement );
|
||||
this.content.appendChild( scrollWrapper );
|
||||
|
||||
// graph
|
||||
|
||||
const graphContainer = document.createElement( 'div' );
|
||||
graphContainer.className = 'graph-container';
|
||||
|
||||
const graph = new Graph();
|
||||
graph.addLine( 'total', 'var( --color-yellow )' );
|
||||
graphContainer.append( graph.domElement );
|
||||
|
||||
// stats
|
||||
|
||||
const graphStats = new Item( 'Graph Stats', '', '' );
|
||||
memoryList.add( graphStats );
|
||||
|
||||
const graphItem = new Item( graphContainer );
|
||||
graphItem.itemRow.childNodes[ 0 ].style.gridColumn = '1 / -1';
|
||||
graphStats.add( graphItem );
|
||||
|
||||
// info
|
||||
|
||||
this.memoryStats = new Item( 'Renderer Info', '', createValueSpan() );
|
||||
this.memoryStats.domElement.firstChild.classList.add( 'no-hover' );
|
||||
memoryList.add( this.memoryStats );
|
||||
|
||||
this.attributes = new Item( 'Attributes', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.attributes );
|
||||
|
||||
this.geometries = new Item( 'Geometries', createValueSpan(), 'N/A' );
|
||||
this.memoryStats.add( this.geometries );
|
||||
|
||||
this.indexAttributes = new Item( 'Index Attributes', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.indexAttributes );
|
||||
|
||||
this.indirectStorageAttributes = new Item( 'Indirect Storage Attributes', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.indirectStorageAttributes );
|
||||
|
||||
this.programs = new Item( 'Programs', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.programs );
|
||||
|
||||
this.readbackBuffers = new Item( 'Readback Buffers', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.readbackBuffers );
|
||||
|
||||
this.renderTargets = new Item( 'Render Targets', createValueSpan(), 'N/A' );
|
||||
this.memoryStats.add( this.renderTargets );
|
||||
|
||||
this.storageAttributes = new Item( 'Storage Attributes', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.storageAttributes );
|
||||
|
||||
this.textures = new Item( 'Textures', createValueSpan(), createValueSpan() );
|
||||
this.memoryStats.add( this.textures );
|
||||
|
||||
this.graph = graph;
|
||||
|
||||
}
|
||||
|
||||
updateGraph( inspector ) {
|
||||
|
||||
const renderer = inspector.getRenderer();
|
||||
if ( ! renderer ) return;
|
||||
|
||||
const memory = renderer.info.memory;
|
||||
|
||||
this.graph.addPoint( 'total', memory.total );
|
||||
|
||||
if ( this.graph.limit === 0 ) this.graph.limit = 1;
|
||||
|
||||
this.graph.update();
|
||||
|
||||
}
|
||||
|
||||
updateText( inspector ) {
|
||||
|
||||
const renderer = inspector.getRenderer();
|
||||
if ( ! renderer ) return;
|
||||
|
||||
const memory = renderer.info.memory;
|
||||
|
||||
setText( this.memoryStats.data[ 2 ], formatBytes( memory.total ) );
|
||||
|
||||
setText( this.attributes.data[ 1 ], memory.attributes.toString() );
|
||||
setText( this.attributes.data[ 2 ], formatBytes( memory.attributesSize ) );
|
||||
setText( this.geometries.data[ 1 ], memory.geometries.toString() );
|
||||
|
||||
setText( this.indexAttributes.data[ 1 ], memory.indexAttributes.toString() );
|
||||
setText( this.indexAttributes.data[ 2 ], formatBytes( memory.indexAttributesSize ) );
|
||||
|
||||
setText( this.indirectStorageAttributes.data[ 1 ], memory.indirectStorageAttributes.toString() );
|
||||
setText( this.indirectStorageAttributes.data[ 2 ], formatBytes( memory.indirectStorageAttributesSize ) );
|
||||
|
||||
setText( this.programs.data[ 1 ], memory.programs.toString() );
|
||||
setText( this.programs.data[ 2 ], formatBytes( memory.programsSize ) );
|
||||
|
||||
setText( this.readbackBuffers.data[ 1 ], memory.readbackBuffers.toString() );
|
||||
setText( this.readbackBuffers.data[ 2 ], formatBytes( memory.readbackBuffersSize ) );
|
||||
|
||||
setText( this.renderTargets.data[ 1 ], memory.renderTargets.toString() );
|
||||
|
||||
setText( this.storageAttributes.data[ 1 ], memory.storageAttributes.toString() );
|
||||
setText( this.storageAttributes.data[ 2 ], formatBytes( memory.storageAttributesSize ) );
|
||||
setText( this.textures.data[ 1 ], memory.textures.toString() );
|
||||
setText( this.textures.data[ 2 ], formatBytes( memory.texturesSize ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Memory };
|
||||
380
node_modules/three/examples/jsm/inspector/tabs/Parameters.js
generated
vendored
Normal file
380
node_modules/three/examples/jsm/inspector/tabs/Parameters.js
generated
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
import { Tab } from '../ui/Tab.js';
|
||||
import { List } from '../ui/List.js';
|
||||
import { Item } from '../ui/Item.js';
|
||||
import { createValueSpan } from '../ui/utils.js';
|
||||
import { ValueString, ValueNumber, ValueSlider, ValueSelect, ValueCheckbox, ValueColor, ValueButton } from '../ui/Values.js';
|
||||
|
||||
class ParametersGroup {
|
||||
|
||||
constructor( parameters, name ) {
|
||||
|
||||
this.parameters = parameters;
|
||||
this.name = name;
|
||||
|
||||
this.paramList = new Item( name );
|
||||
|
||||
this.objects = [];
|
||||
|
||||
}
|
||||
|
||||
close() {
|
||||
|
||||
this.paramList.close();
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
add( object, property, ...params ) {
|
||||
|
||||
const value = object[ property ];
|
||||
const type = typeof value;
|
||||
|
||||
let item = null;
|
||||
|
||||
if ( typeof params[ 0 ] === 'object' ) {
|
||||
|
||||
item = this.addSelect( object, property, params[ 0 ] );
|
||||
|
||||
} else if ( type === 'number' ) {
|
||||
|
||||
if ( params.length >= 2 ) {
|
||||
|
||||
item = this.addSlider( object, property, ...params );
|
||||
|
||||
} else {
|
||||
|
||||
item = this.addNumber( object, property, ...params );
|
||||
|
||||
}
|
||||
|
||||
} else if ( type === 'boolean' ) {
|
||||
|
||||
item = this.addBoolean( object, property );
|
||||
|
||||
} else if ( type === 'string' ) {
|
||||
|
||||
item = this.addString( object, property );
|
||||
|
||||
} else if ( type === 'function' ) {
|
||||
|
||||
item = this.addButton( object, property, ...params );
|
||||
|
||||
}
|
||||
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
_addParameter( object, property, editor, subItem ) {
|
||||
|
||||
editor.name = ( name ) => {
|
||||
|
||||
subItem.data[ 0 ].textContent = name;
|
||||
|
||||
return editor;
|
||||
|
||||
};
|
||||
|
||||
editor.listen = () => {
|
||||
|
||||
const update = () => {
|
||||
|
||||
const value = editor.getValue();
|
||||
const propertyValue = object[ property ];
|
||||
|
||||
if ( value !== propertyValue ) {
|
||||
|
||||
editor.setValue( propertyValue );
|
||||
|
||||
}
|
||||
|
||||
requestAnimationFrame( update );
|
||||
|
||||
};
|
||||
|
||||
requestAnimationFrame( update );
|
||||
|
||||
return editor;
|
||||
|
||||
};
|
||||
|
||||
|
||||
this._registerParameter( object, property, editor, subItem );
|
||||
|
||||
}
|
||||
|
||||
_registerParameter( object, property, editor, subItem ) {
|
||||
|
||||
this.objects.push( { object: object, key: property, editor: editor, subItem: subItem } );
|
||||
|
||||
}
|
||||
|
||||
addString( object, property ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueString( { value } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addFolder( name ) {
|
||||
|
||||
const group = new ParametersGroup( this.parameters, name );
|
||||
|
||||
this.paramList.add( group.paramList );
|
||||
|
||||
return group;
|
||||
|
||||
}
|
||||
|
||||
addBoolean( object, property ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueCheckbox( { value } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
// extends logic to toggle checkbox when clicking on the row
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
|
||||
itemRow.classList.add( 'actionable' );
|
||||
itemRow.addEventListener( 'click', ( e ) => {
|
||||
|
||||
if ( e.target.closest( 'label' ) ) return;
|
||||
|
||||
const checkbox = itemRow.querySelector( 'input[type="checkbox"]' );
|
||||
|
||||
if ( checkbox ) {
|
||||
|
||||
checkbox.checked = ! checkbox.checked;
|
||||
checkbox.dispatchEvent( new Event( 'change' ) );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addSelect( object, property, options ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueSelect( { options, value } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addColor( object, property ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueColor( { value } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addSlider( object, property, min = 0, max = 1, step = 0.01 ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueSlider( { value, min, max, step } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addNumber( object, property, ...params ) {
|
||||
|
||||
const value = object[ property ];
|
||||
const [ min, max ] = params;
|
||||
|
||||
const editor = new ValueNumber( { value, min, max } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const description = createValueSpan();
|
||||
description.textContent = property;
|
||||
|
||||
const subItem = new Item( description, editor.domElement );
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
this._addParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
addButton( object, property ) {
|
||||
|
||||
const value = object[ property ];
|
||||
|
||||
const editor = new ValueButton( { text: property, value } );
|
||||
editor.addEventListener( 'change', ( { value } ) => {
|
||||
|
||||
object[ property ] = value;
|
||||
|
||||
} );
|
||||
|
||||
const subItem = new Item( editor.domElement );
|
||||
subItem.itemRow.childNodes[ 0 ].style.gridColumn = '1 / -1';
|
||||
this.paramList.add( subItem );
|
||||
|
||||
const itemRow = subItem.domElement.firstChild;
|
||||
itemRow.classList.add( 'actionable' );
|
||||
|
||||
// extend object property
|
||||
|
||||
editor.name = ( name ) => {
|
||||
|
||||
editor.domElement.childNodes[ 0 ].textContent = name;
|
||||
|
||||
return editor;
|
||||
|
||||
};
|
||||
|
||||
this._registerParameter( object, property, editor, subItem );
|
||||
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Parameters extends Tab {
|
||||
|
||||
constructor( options = {} ) {
|
||||
|
||||
super( options.name || 'Parameters', options );
|
||||
|
||||
const paramList = new List( 'Property', 'Value' );
|
||||
paramList.domElement.classList.add( 'parameters' );
|
||||
paramList.setGridStyle( '.5fr 1fr' );
|
||||
paramList.domElement.style.minWidth = '300px';
|
||||
|
||||
const scrollWrapper = document.createElement( 'div' );
|
||||
scrollWrapper.className = 'list-scroll-wrapper';
|
||||
scrollWrapper.appendChild( paramList.domElement );
|
||||
this.content.appendChild( scrollWrapper );
|
||||
|
||||
this.paramList = paramList;
|
||||
|
||||
this.groups = [];
|
||||
|
||||
}
|
||||
|
||||
createGroup( name ) {
|
||||
|
||||
const group = new ParametersGroup( this, name );
|
||||
|
||||
this.paramList.add( group.paramList );
|
||||
this.groups.push( group );
|
||||
|
||||
return group;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Parameters };
|
||||
268
node_modules/three/examples/jsm/inspector/tabs/Performance.js
generated
vendored
Normal file
268
node_modules/three/examples/jsm/inspector/tabs/Performance.js
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
import { Tab } from '../ui/Tab.js';
|
||||
import { List } from '../ui/List.js';
|
||||
import { Graph } from '../ui/Graph.js';
|
||||
import { Item } from '../ui/Item.js';
|
||||
import { createValueSpan, setText } from '../ui/utils.js';
|
||||
|
||||
class Performance extends Tab {
|
||||
|
||||
constructor( options = {} ) {
|
||||
|
||||
super( 'Performance', options );
|
||||
|
||||
const perfList = new List( 'Name', 'CPU', 'GPU', 'Total' );
|
||||
perfList.setGridStyle( 'minmax(200px, 2fr) 80px 80px 80px' );
|
||||
perfList.domElement.style.minWidth = '600px';
|
||||
|
||||
const scrollWrapper = document.createElement( 'div' );
|
||||
scrollWrapper.className = 'list-scroll-wrapper';
|
||||
scrollWrapper.appendChild( perfList.domElement );
|
||||
this.content.appendChild( scrollWrapper );
|
||||
|
||||
//
|
||||
|
||||
const graphContainer = document.createElement( 'div' );
|
||||
graphContainer.className = 'graph-container';
|
||||
|
||||
const graph = new Graph();
|
||||
graph.addLine( 'fps', 'var( --color-fps )' );
|
||||
//graph.addLine( 'gpu', 'var( --color-yellow )' );
|
||||
graphContainer.append( graph.domElement );
|
||||
|
||||
//
|
||||
|
||||
/*
|
||||
const label = document.createElement( 'label' );
|
||||
label.className = 'custom-checkbox';
|
||||
|
||||
const checkbox = document.createElement( 'input' );
|
||||
checkbox.type = 'checkbox';
|
||||
|
||||
const checkmark = document.createElement( 'span' );
|
||||
checkmark.className = 'checkmark';
|
||||
|
||||
label.appendChild( checkbox );
|
||||
label.appendChild( checkmark );
|
||||
*/
|
||||
|
||||
const graphStats = new Item( 'Graph Stats', createValueSpan(), createValueSpan(), createValueSpan( 'graph-fps-counter' ) );
|
||||
perfList.add( graphStats );
|
||||
|
||||
const graphItem = new Item( graphContainer );
|
||||
graphItem.itemRow.childNodes[ 0 ].style.gridColumn = '1 / -1';
|
||||
graphStats.add( graphItem );
|
||||
|
||||
//
|
||||
|
||||
const frameStats = new Item( 'Frame Stats', createValueSpan(), createValueSpan(), createValueSpan() );
|
||||
perfList.add( frameStats );
|
||||
|
||||
const miscellaneous = new Item( 'Miscellaneous & Idle', createValueSpan(), createValueSpan(), createValueSpan() );
|
||||
miscellaneous.domElement.firstChild.style.backgroundColor = '#00ff0b1a';
|
||||
miscellaneous.domElement.firstChild.classList.add( 'no-hover' );
|
||||
frameStats.add( miscellaneous );
|
||||
|
||||
//
|
||||
|
||||
this.notInUse = new Map();
|
||||
this.frameStats = frameStats;
|
||||
this.graphStats = graphStats;
|
||||
this.graph = graph;
|
||||
this.miscellaneous = miscellaneous;
|
||||
|
||||
//
|
||||
|
||||
this.currentRender = null;
|
||||
this.currentItem = null;
|
||||
this.frameItems = new Map();
|
||||
|
||||
}
|
||||
|
||||
resolveStats( inspector, stats ) {
|
||||
|
||||
const data = inspector.getStatsData( stats.cid );
|
||||
|
||||
let item = data.item;
|
||||
|
||||
if ( item === undefined ) {
|
||||
|
||||
item = new Item( createValueSpan(), createValueSpan(), createValueSpan(), createValueSpan() );
|
||||
|
||||
if ( stats.name ) {
|
||||
|
||||
if ( stats.isComputeStats === true ) {
|
||||
|
||||
stats.name = `${ stats.name } [ Compute ]`;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
stats.name = `Unnamed ${ stats.cid }`;
|
||||
|
||||
}
|
||||
|
||||
item.userData.name = stats.name;
|
||||
|
||||
this.currentItem.add( item );
|
||||
data.item = item;
|
||||
|
||||
} else {
|
||||
|
||||
item.userData.name = stats.name;
|
||||
|
||||
if ( this.notInUse.has( stats.cid ) ) {
|
||||
|
||||
item.domElement.firstElementChild.classList.remove( 'alert' );
|
||||
|
||||
this.notInUse.delete( stats.cid );
|
||||
|
||||
}
|
||||
|
||||
const statsIndex = stats.parent.children.indexOf( stats );
|
||||
|
||||
if ( item.parent === null || item.parent.children.indexOf( item ) !== statsIndex ) {
|
||||
|
||||
this.currentItem.add( item, statsIndex );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let name = item.userData.name;
|
||||
|
||||
if ( stats.isComputeStats ) {
|
||||
|
||||
name += ' [ Compute ]';
|
||||
|
||||
}
|
||||
|
||||
setText( item.data[ 0 ], name );
|
||||
setText( item.data[ 1 ], data.cpu.toFixed( 2 ) );
|
||||
setText( item.data[ 2 ], stats.gpuNotAvailable === true ? '-' : data.gpu.toFixed( 2 ) );
|
||||
setText( item.data[ 3 ], data.total.toFixed( 2 ) );
|
||||
|
||||
//
|
||||
|
||||
const previousItem = this.currentItem;
|
||||
|
||||
this.currentItem = item;
|
||||
|
||||
for ( const child of stats.children ) {
|
||||
|
||||
this.resolveStats( inspector, child );
|
||||
|
||||
}
|
||||
|
||||
this.currentItem = previousItem;
|
||||
|
||||
this.frameItems.set( stats.cid, item );
|
||||
|
||||
}
|
||||
|
||||
updateGraph( inspector/*, frame*/ ) {
|
||||
|
||||
this.graph.addPoint( 'fps', inspector.fps );
|
||||
this.graph.update();
|
||||
|
||||
}
|
||||
|
||||
addNotInUse( cid, item ) {
|
||||
|
||||
item.domElement.firstElementChild.classList.add( 'alert' );
|
||||
|
||||
this.notInUse.set( cid, {
|
||||
item,
|
||||
time: performance.now()
|
||||
} );
|
||||
|
||||
this.updateNotInUse( cid );
|
||||
|
||||
}
|
||||
|
||||
updateNotInUse( cid ) {
|
||||
|
||||
const { item, time } = this.notInUse.get( cid );
|
||||
|
||||
const current = performance.now();
|
||||
const duration = 5;
|
||||
const remaining = duration - Math.floor( ( current - time ) / 1000 );
|
||||
|
||||
if ( remaining >= 0 ) {
|
||||
|
||||
const counter = '*'.repeat( Math.max( 0, remaining ) );
|
||||
const element = item.domElement.querySelector( '.list-item-cell .value' );
|
||||
|
||||
setText( element, item.userData.name + ' (not in use) ' + counter );
|
||||
|
||||
} else {
|
||||
|
||||
item.domElement.firstElementChild.classList.remove( 'alert' );
|
||||
item.parent.remove( item );
|
||||
|
||||
this.notInUse.delete( cid );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateText( inspector, frame ) {
|
||||
|
||||
const oldFrameItems = new Map( this.frameItems );
|
||||
|
||||
this.frameItems.clear();
|
||||
this.currentItem = this.frameStats;
|
||||
|
||||
for ( const child of frame.children ) {
|
||||
|
||||
this.resolveStats( inspector, child );
|
||||
|
||||
}
|
||||
|
||||
// remove unused frame items
|
||||
|
||||
for ( const [ cid, item ] of oldFrameItems ) {
|
||||
|
||||
if ( ! this.frameItems.has( cid ) ) {
|
||||
|
||||
this.addNotInUse( cid, item );
|
||||
|
||||
oldFrameItems.delete( cid );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// update not in use items
|
||||
|
||||
for ( const cid of this.notInUse.keys() ) {
|
||||
|
||||
this.updateNotInUse( cid );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
setText( 'graph-fps-counter', inspector.fps.toFixed() + ' FPS' );
|
||||
|
||||
//
|
||||
|
||||
setText( this.frameStats.data[ 1 ], frame.cpu.toFixed( 2 ) );
|
||||
setText( this.frameStats.data[ 2 ], frame.gpu.toFixed( 2 ) );
|
||||
setText( this.frameStats.data[ 3 ], frame.total.toFixed( 2 ) );
|
||||
|
||||
//
|
||||
|
||||
setText( this.miscellaneous.data[ 1 ], frame.miscellaneous.toFixed( 2 ) );
|
||||
setText( this.miscellaneous.data[ 2 ], '-' );
|
||||
setText( this.miscellaneous.data[ 3 ], frame.miscellaneous.toFixed( 2 ) );
|
||||
|
||||
//
|
||||
|
||||
this.currentItem = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Performance };
|
||||
264
node_modules/three/examples/jsm/inspector/tabs/Settings.js
generated
vendored
Normal file
264
node_modules/three/examples/jsm/inspector/tabs/Settings.js
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
import { Parameters } from './Parameters.js';
|
||||
import { WebGPURenderer, WebGLBackend, Node } from 'three/webgpu';
|
||||
import { getItem, setItem } from '../Inspector.js';
|
||||
|
||||
const _EXTENSIONS_PATH = '../extensions/extensions.json';
|
||||
|
||||
const _init = WebGPURenderer.prototype.init;
|
||||
|
||||
function forceWebGL( enable ) {
|
||||
|
||||
if ( enable ) {
|
||||
|
||||
WebGPURenderer.prototype.init = async function () {
|
||||
|
||||
if ( this.backend.isWebGLBackend !== true ) {
|
||||
|
||||
const parameters = this.backend.parameters;
|
||||
|
||||
this.backend = new WebGLBackend( parameters );
|
||||
|
||||
}
|
||||
|
||||
return _init.call( this );
|
||||
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
WebGPURenderer.prototype.init = _init;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let _state = null;
|
||||
|
||||
function _loadState() {
|
||||
|
||||
if ( _state !== null ) return _state;
|
||||
|
||||
const settings = getItem( 'settings' );
|
||||
|
||||
_state = {
|
||||
forceWebGL: settings.forceWebGL !== undefined ? settings.forceWebGL : false,
|
||||
captureStackTrace: settings.captureStackTrace !== undefined ? settings.captureStackTrace : false,
|
||||
activeExtensions: settings.activeExtensions !== undefined ? settings.activeExtensions : {}
|
||||
};
|
||||
|
||||
if ( _state.forceWebGL ) {
|
||||
|
||||
forceWebGL( true );
|
||||
|
||||
}
|
||||
|
||||
if ( _state.captureStackTrace ) {
|
||||
|
||||
Node.captureStackTrace = true;
|
||||
|
||||
}
|
||||
|
||||
return _state;
|
||||
|
||||
}
|
||||
|
||||
function _saveState() {
|
||||
|
||||
setItem( 'settings', {
|
||||
forceWebGL: _state.forceWebGL,
|
||||
captureStackTrace: _state.captureStackTrace,
|
||||
activeExtensions: _state.activeExtensions
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
_loadState();
|
||||
|
||||
//
|
||||
|
||||
class Settings extends Parameters {
|
||||
|
||||
constructor() {
|
||||
|
||||
super( { name: 'Settings' } );
|
||||
|
||||
this.extensions = {};
|
||||
|
||||
const currentState = _loadState();
|
||||
|
||||
// UI
|
||||
|
||||
const rendererGroup = this.createGroup( 'Renderer' );
|
||||
|
||||
rendererGroup.add( currentState, 'forceWebGL' ).name( 'Force WebGL' ).onChange( ( enable ) => {
|
||||
|
||||
forceWebGL( enable );
|
||||
_saveState();
|
||||
|
||||
location.reload();
|
||||
|
||||
} );
|
||||
|
||||
rendererGroup.add( currentState, 'captureStackTrace' ).name( 'Capture Stack Trace' ).onChange( ( enable ) => {
|
||||
|
||||
Node.captureStackTrace = enable;
|
||||
_saveState();
|
||||
|
||||
location.reload();
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
const extensionsGroup = this.createGroup( 'Extensions' );
|
||||
|
||||
this._getExtensions().then( extensions => {
|
||||
|
||||
for ( const extension of extensions ) {
|
||||
|
||||
extension.active = false;
|
||||
extension.loaded = false;
|
||||
extension.tab = null;
|
||||
|
||||
this.extensions[ extension.name ] = extension;
|
||||
|
||||
extension.ui = extensionsGroup.add( { [ extension.name ]: false }, extension.name ).onChange( async ( value ) => {
|
||||
|
||||
this.setActiveExtension( extension.name, value );
|
||||
|
||||
// User preference
|
||||
|
||||
if ( value ) {
|
||||
|
||||
_state.activeExtensions[ extension.name ] = {
|
||||
name: extension.name,
|
||||
url: extension.url
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
delete _state.activeExtensions[ extension.name ];
|
||||
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this._updateExtensionUI( extension );
|
||||
|
||||
_saveState();
|
||||
|
||||
} );
|
||||
|
||||
// Set user-defined state
|
||||
|
||||
if ( _state.activeExtensions[ extension.name ] !== undefined ) {
|
||||
|
||||
extension.ui.setValue( true );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
async setActiveExtension( name, value ) {
|
||||
|
||||
const extension = this.extensions[ name ];
|
||||
const inspector = this.inspector;
|
||||
|
||||
if ( extension ) {
|
||||
|
||||
if ( value ) {
|
||||
|
||||
await this._loadExtension( inspector, extension );
|
||||
|
||||
} else {
|
||||
|
||||
await this._unloadExtension( inspector, extension );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_updateExtensionUI( extension ) {
|
||||
|
||||
const forceActive = extension.active && _state.activeExtensions[ extension.name ] === undefined;
|
||||
|
||||
if ( forceActive ) {
|
||||
|
||||
extension.ui.checkbox.checked = true;
|
||||
extension.ui.domElement.style.setProperty( '--accent-color', 'var(--color-green)' );
|
||||
|
||||
} else {
|
||||
|
||||
extension.ui.domElement.style.removeProperty( '--accent-color' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async _unloadExtension( inspector, extension ) {
|
||||
|
||||
if ( extension.active === false ) return;
|
||||
|
||||
//
|
||||
|
||||
inspector.removeTab( extension.tab );
|
||||
|
||||
extension.active = false;
|
||||
extension.loaded = false;
|
||||
extension.tab = null;
|
||||
|
||||
this._updateExtensionUI( extension );
|
||||
|
||||
this.dispatchEvent( { type: 'extensionremoved', name: extension.name } );
|
||||
|
||||
}
|
||||
|
||||
async _loadExtension( inspector, extension ) {
|
||||
|
||||
if ( extension.active === true ) return;
|
||||
|
||||
//
|
||||
|
||||
extension.active = true;
|
||||
|
||||
const extUrl = new URL( extension.url, new URL( _EXTENSIONS_PATH, import.meta.url ) ).href;
|
||||
|
||||
const module = await import( extUrl );
|
||||
|
||||
const keys = Object.keys( module );
|
||||
const ExtensionClass = module[ keys[ 0 ] ];
|
||||
const extensionTab = new ExtensionClass();
|
||||
|
||||
inspector.addTab( extensionTab );
|
||||
|
||||
extension.loaded = true;
|
||||
extension.tab = extensionTab;
|
||||
|
||||
this._updateExtensionUI( extension );
|
||||
|
||||
this.dispatchEvent( { type: 'extensionadded', name: extension.name, tab: extensionTab } );
|
||||
|
||||
}
|
||||
|
||||
async _getExtensions() {
|
||||
|
||||
const url = new URL( _EXTENSIONS_PATH, import.meta.url );
|
||||
|
||||
const extensions = await fetch( url ).then( res => res.json() );
|
||||
|
||||
return extensions;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Settings };
|
||||
1611
node_modules/three/examples/jsm/inspector/tabs/Timeline.js
generated
vendored
Normal file
1611
node_modules/three/examples/jsm/inspector/tabs/Timeline.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
268
node_modules/three/examples/jsm/inspector/tabs/Viewer.js
generated
vendored
Normal file
268
node_modules/three/examples/jsm/inspector/tabs/Viewer.js
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
import { Tab } from '../ui/Tab.js';
|
||||
import { List } from '../ui/List.js';
|
||||
import { Item } from '../ui/Item.js';
|
||||
import { splitPath, splitCamelCase } from '../ui/utils.js';
|
||||
|
||||
import { RendererUtils, NoToneMapping, LinearSRGBColorSpace, QuadMesh, NodeMaterial, CanvasTarget } from 'three/webgpu';
|
||||
import { renderOutput, vec2, vec3, vec4, Fn, screenUV, step, OnMaterialUpdate, uniform } from 'three/tsl';
|
||||
|
||||
const aspectRatioUV = /*@__PURE__*/ Fn( ( [ uv, textureNode ] ) => {
|
||||
|
||||
const aspect = uniform( 0 );
|
||||
|
||||
OnMaterialUpdate( () => {
|
||||
|
||||
const { width, height } = textureNode.value;
|
||||
|
||||
aspect.value = width / height;
|
||||
|
||||
} );
|
||||
|
||||
const centered = uv.sub( 0.5 );
|
||||
const corrected = vec2( centered.x.div( aspect ), centered.y );
|
||||
const finalUV = corrected.add( 0.5 );
|
||||
|
||||
const inBounds = step( 0.0, finalUV.x ).mul( step( finalUV.x, 1.0 ) ).mul( step( 0.0, finalUV.y ) ).mul( step( finalUV.y, 1.0 ) );
|
||||
|
||||
return vec3( finalUV, inBounds );
|
||||
|
||||
} );
|
||||
|
||||
class Viewer extends Tab {
|
||||
|
||||
constructor( options = {} ) {
|
||||
|
||||
super( 'Viewer', options );
|
||||
|
||||
const nodeList = new List( 'Viewer', 'Name' );
|
||||
nodeList.setGridStyle( '150px minmax(200px, 2fr)' );
|
||||
nodeList.domElement.style.minWidth = '400px';
|
||||
|
||||
const scrollWrapper = document.createElement( 'div' );
|
||||
scrollWrapper.className = 'list-scroll-wrapper';
|
||||
scrollWrapper.appendChild( nodeList.domElement );
|
||||
this.content.appendChild( scrollWrapper );
|
||||
|
||||
const nodes = new Item( 'Nodes' );
|
||||
nodeList.add( nodes );
|
||||
|
||||
//
|
||||
|
||||
this.itemLibrary = new Map();
|
||||
this.folderLibrary = new Map();
|
||||
this.canvasNodes = new Map();
|
||||
this.currentDataList = [];
|
||||
this.nodeList = nodeList;
|
||||
this.nodes = nodes;
|
||||
|
||||
}
|
||||
|
||||
getFolder( name ) {
|
||||
|
||||
let folder = this.folderLibrary.get( name );
|
||||
|
||||
if ( folder === undefined ) {
|
||||
|
||||
folder = new Item( name );
|
||||
|
||||
this.folderLibrary.set( name, folder );
|
||||
this.nodeList.add( folder );
|
||||
|
||||
}
|
||||
|
||||
return folder;
|
||||
|
||||
}
|
||||
|
||||
addNodeItem( canvasData ) {
|
||||
|
||||
let item = this.itemLibrary.get( canvasData.id );
|
||||
|
||||
if ( item === undefined ) {
|
||||
|
||||
const name = canvasData.name;
|
||||
const domElement = canvasData.canvasTarget.domElement;
|
||||
|
||||
item = new Item( domElement, name );
|
||||
item.itemRow.children[ 1 ].style[ 'justify-content' ] = 'flex-start';
|
||||
this.itemLibrary.set( canvasData.id, item );
|
||||
|
||||
}
|
||||
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
getCanvasDataByNode( renderer, node ) {
|
||||
|
||||
let canvasData = this.canvasNodes.get( node );
|
||||
|
||||
if ( canvasData === undefined ) {
|
||||
|
||||
const canvas = document.createElement( 'canvas' );
|
||||
|
||||
const canvasTarget = new CanvasTarget( canvas );
|
||||
canvasTarget.setPixelRatio( window.devicePixelRatio );
|
||||
canvasTarget.setSize( 140, 140 );
|
||||
|
||||
const id = node.id;
|
||||
|
||||
const { path, name } = splitPath( splitCamelCase( node.getName() || '(unnamed)' ) );
|
||||
|
||||
const target = node.context( { getUV: ( textureNode ) => {
|
||||
|
||||
const uvData = aspectRatioUV( screenUV, textureNode );
|
||||
const correctedUV = uvData.xy;
|
||||
const mask = uvData.z;
|
||||
|
||||
return correctedUV.mul( mask );
|
||||
|
||||
} } );
|
||||
|
||||
let output = vec4( vec3( target ), 1 );
|
||||
output = renderOutput( output, NoToneMapping, renderer.outputColorSpace );
|
||||
output = output.context( { inspector: true } );
|
||||
|
||||
const material = new NodeMaterial();
|
||||
material.outputNode = output;
|
||||
|
||||
const quad = new QuadMesh( material );
|
||||
quad.name = 'Viewer - ' + name;
|
||||
|
||||
canvasData = {
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
node,
|
||||
quad,
|
||||
canvasTarget,
|
||||
material
|
||||
};
|
||||
|
||||
this.canvasNodes.set( node, canvasData );
|
||||
|
||||
}
|
||||
|
||||
return canvasData;
|
||||
|
||||
}
|
||||
|
||||
update( inspector ) {
|
||||
|
||||
const renderer = inspector.getRenderer();
|
||||
const nodes = inspector.getNodes();
|
||||
|
||||
if ( nodes.length > 0 ) {
|
||||
|
||||
if ( ! renderer.backend.isWebGPUBackend ) {
|
||||
|
||||
inspector.resolveConsoleOnce( 'warn', 'Inspector: Viewer is only available with WebGPU.' );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ( ! this.isVisible ) {
|
||||
|
||||
this.show();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( ! this.isActive ) return;
|
||||
|
||||
const canvasDataList = nodes.map( node => this.getCanvasDataByNode( renderer, node ) );
|
||||
|
||||
//
|
||||
|
||||
const previousDataList = [ ...this.currentDataList ];
|
||||
|
||||
// remove old
|
||||
|
||||
for ( const canvasData of previousDataList ) {
|
||||
|
||||
if ( this.itemLibrary.has( canvasData.id ) && canvasDataList.indexOf( canvasData ) === - 1 ) {
|
||||
|
||||
const item = this.itemLibrary.get( canvasData.id );
|
||||
const parent = item.parent;
|
||||
|
||||
parent.remove( item );
|
||||
|
||||
if ( this.folderLibrary.has( parent.data[ 0 ] ) && parent.children.length === 0 ) {
|
||||
|
||||
parent.parent.remove( parent );
|
||||
|
||||
this.folderLibrary.delete( parent.data[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
this.itemLibrary.delete( canvasData.id );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const indexes = {};
|
||||
|
||||
for ( const canvasData of canvasDataList ) {
|
||||
|
||||
const item = this.addNodeItem( canvasData );
|
||||
const previousCanvasTarget = renderer.getCanvasTarget();
|
||||
|
||||
const path = canvasData.path;
|
||||
|
||||
if ( path ) {
|
||||
|
||||
const folder = this.getFolder( path );
|
||||
|
||||
if ( indexes[ path ] === undefined ) {
|
||||
|
||||
indexes[ path ] = 0;
|
||||
|
||||
}
|
||||
|
||||
if ( folder.parent === null || item.parent !== folder || folder.children.indexOf( item ) !== indexes[ path ] ) {
|
||||
|
||||
folder.add( item );
|
||||
|
||||
}
|
||||
|
||||
indexes[ path ] ++;
|
||||
|
||||
} else {
|
||||
|
||||
if ( ! item.parent ) {
|
||||
|
||||
this.nodes.add( item );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.currentDataList = canvasDataList;
|
||||
|
||||
//
|
||||
|
||||
const state = RendererUtils.resetRendererState( renderer );
|
||||
|
||||
renderer.toneMapping = NoToneMapping;
|
||||
renderer.outputColorSpace = LinearSRGBColorSpace;
|
||||
|
||||
renderer.setCanvasTarget( canvasData.canvasTarget );
|
||||
|
||||
canvasData.quad.render( renderer );
|
||||
|
||||
renderer.setCanvasTarget( previousCanvasTarget );
|
||||
|
||||
RendererUtils.restoreRendererState( renderer, state );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Viewer };
|
||||
Reference in New Issue
Block a user