123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /**
- * @author mrdoob / http://mrdoob.com/
- */
- var Script = function ( editor ) {
- var signals = editor.signals;
- var container = new UI.Panel();
- container.setId( 'script' );
- container.setPosition( 'absolute' );
- container.setBackgroundColor( '#272822' );
- container.setDisplay( 'none' );
- var header = new UI.Panel();
- header.setPadding( '10px' );
- container.add( header );
- var title = new UI.Text().setColor( '#fff' );
- header.add( title );
- var buttonSVG = ( function () {
- var svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
- svg.setAttribute( 'width', 32 );
- svg.setAttribute( 'height', 32 );
- var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
- path.setAttribute( 'd', 'M 12,12 L 22,22 M 22,12 12,22' );
- path.setAttribute( 'stroke', '#fff' );
- svg.appendChild( path );
- return svg;
- } )();
- var close = new UI.Element( buttonSVG );
- close.setPosition( 'absolute' );
- close.setTop( '3px' );
- close.setRight( '1px' );
- close.setCursor( 'pointer' );
- close.onClick( function () {
- container.setDisplay( 'none' );
- } );
- header.add( close );
- var delay;
- var currentMode;
- var currentScript;
- var currentObject;
- var codemirror = CodeMirror( container.dom, {
- value: '',
- lineNumbers: true,
- matchBrackets: true,
- indentWithTabs: true,
- tabSize: 4,
- indentUnit: 4
- } );
- codemirror.setOption( 'theme', 'monokai' );
- codemirror.on( 'change', function () {
- clearTimeout( delay );
- delay = setTimeout( function () {
- var value = codemirror.getValue();
- if ( ! validate( value ) ) return;
- if ( typeof( currentScript ) === 'object' ) {
- currentScript.source = value;
- signals.scriptChanged.dispatch( currentScript );
- return;
- }
- switch ( currentScript ) {
- case 'vertexShader':
- currentObject.vertexShader = value;
- break;
- case 'fragmentShader':
- currentObject.fragmentShader = value;
- break;
- case 'programInfo':
- var json = JSON.parse( value );
- currentObject.defines = json.defines;
- currentObject.uniforms = json.uniforms;
- currentObject.attributes = json.attributes;
- }
- currentObject.needsUpdate = true;
- signals.materialChanged.dispatch( currentObject );
- }, 200 );
- });
- // prevent backspace from deleting objects
- var wrapper = codemirror.getWrapperElement();
- wrapper.addEventListener( 'keydown', function ( event ) {
- event.stopPropagation();
- } );
- // validate
- var errorLines = [];
- var widgets = [];
- var validate = function ( string ) {
- var errors;
- return codemirror.operation( function () {
- while ( errorLines.length > 0 ) {
- codemirror.removeLineClass( errorLines.shift(), 'background', 'errorLine' );
- }
- while ( widgets.length > 0 ) {
- codemirror.removeLineWidget( widgets.shift() );
- }
- //
- switch ( currentMode ) {
- case 'javascript':
- try {
- var syntax = esprima.parse( string, { tolerant: true } );
- errors = syntax.errors;
- } catch ( error ) {
- errors = [
- { lineNumber: error.lineNumber,message: error.message }
- ];
- }
- for ( var i = 0; i < errors.length; i ++ ) {
- var error = errors[ i ];
- error.message = error.message.replace(/Line [0-9]+: /, '');
- }
- break;
- case 'json':
- errors = [];
- jsonlint.parseError = function ( message, info ) {
- message = message.split('\n')[3];
- errors.push({
- lineNumber: info.loc.first_line,
- message: message
- });
- };
- try {
- jsonlint.parse( string );
- } catch ( error ) {
- // ignore failed error recovery
- }
- break;
- case 'glsl':
- // TODO validate GLSL (compiling shader?)
- default:
- errors = [];
- }
- for ( var i = 0; i < errors.length; i ++ ) {
- var error = errors[ i ];
- var message = document.createElement( 'div' );
- message.className = 'esprima-error';
- message.textContent = error.message;
- var lineNumber = error.lineNumber - 1;
- errorLines.push( lineNumber );
- codemirror.addLineClass( lineNumber, 'background', 'errorLine' );
- var widget = codemirror.addLineWidget( lineNumber, message );
- widgets.push( widget );
- }
- return errorLines.length === 0;
- });
- };
- //
- signals.editorCleared.add( function () {
- container.setDisplay( 'none' );
- } );
- signals.editScript.add( function ( object, script ) {
- var mode, name, source;
- if ( typeof( script ) === 'object' ) {
- mode = 'javascript';
- name = script.name;
- source = script.source;
- } else {
- switch ( script ) {
- case 'vertexShader':
- mode = 'glsl';
- name = 'Vertex Shader';
- source = object.vertexShader || "";
- break;
- case 'fragmentShader':
- mode = 'glsl';
- name = 'Fragment Shader';
- source = object.fragmentShader || "";
- break;
- case 'programInfo':
- mode = 'json';
- name = 'Program Properties';
- var json = {
- defines: object.defines,
- uniforms: object.uniforms,
- attributes: object.attributes
- };
- source = JSON.stringify( json, null, '\t' );
- }
- }
- currentMode = mode;
- currentScript = script;
- currentObject = object;
- title.setValue( object.name + ' / ' + name );
- container.setDisplay( '' );
- codemirror.setValue( source );
- if (mode === 'json' ) mode = { name: 'javascript', json: true };
- codemirror.setOption( 'mode', mode );
- } );
- return container;
- };
|