mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2026-02-01 16:08:17 +00:00
添加three.js官方动画编辑器。
This commit is contained in:
parent
dcc86505a2
commit
3d5418e69f
217
ShadowEditor.Web/src/editor/animation/Code.js
Normal file
217
ShadowEditor.Web/src/editor/animation/Code.js
Normal file
@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Code = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'effect' );
|
||||
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 errorLine = null;
|
||||
|
||||
var currentEffect = null;
|
||||
var currentInclude = null;
|
||||
|
||||
var codemirror = CodeMirror( container.dom, {
|
||||
value: '',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
matchBrackets: true,
|
||||
indentWithTabs: true,
|
||||
tabSize: 4,
|
||||
indentUnit: 4,
|
||||
mode: 'javascript'
|
||||
} );
|
||||
codemirror.setOption( 'theme', 'monokai' );
|
||||
codemirror.on( 'change', function () {
|
||||
|
||||
if ( codemirror.state.focused === false ) return;
|
||||
|
||||
clearTimeout( delay );
|
||||
delay = setTimeout( function () {
|
||||
|
||||
if ( errorLine ) {
|
||||
|
||||
codemirror.removeLineClass( errorLine, 'CodeMirror-errorLine' );
|
||||
errorLine = null;
|
||||
|
||||
}
|
||||
|
||||
if ( currentInclude !== null ) {
|
||||
|
||||
currentInclude.source = codemirror.getValue();
|
||||
|
||||
editor.signals.includeChanged.dispatch();
|
||||
|
||||
} else if ( currentEffect !== null ) {
|
||||
|
||||
var error;
|
||||
var currentSource = currentEffect.source;
|
||||
|
||||
editor.timeline.reset();
|
||||
|
||||
try {
|
||||
|
||||
currentEffect.source = codemirror.getValue();
|
||||
editor.compileEffect( currentEffect );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
error = e.name + ' : ' + e.message; // e.stack, e.columnNumber, e.lineNumber
|
||||
|
||||
if ( /Chrome/i.test( navigator.userAgent ) ) {
|
||||
|
||||
var result = /<anonymous>:([0-9]+):([0-9+])/g.exec( e.stack );
|
||||
if ( result !== null ) errorLine = parseInt( result[ 1 ] ) - 3;
|
||||
|
||||
} else if ( /Firefox/i.test( navigator.userAgent ) ) {
|
||||
|
||||
var result = /Function:([0-9]+):([0-9+])/g.exec( e.stack );
|
||||
if ( result !== null ) errorLine = parseInt( result[ 1 ] ) - 1;
|
||||
|
||||
}
|
||||
|
||||
if ( errorLine !== null ) {
|
||||
|
||||
codemirror.addLineClass( errorLine, 'errorLine', 'CodeMirror-errorLine' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
editor.timeline.update( editor.player.currentTime );
|
||||
|
||||
if ( error !== undefined ) {
|
||||
|
||||
errorDiv.setDisplay( '' );
|
||||
errorText.setValue( '⌦ ' + error );
|
||||
|
||||
currentEffect.source = currentSource;
|
||||
|
||||
} else {
|
||||
|
||||
errorDiv.setDisplay( 'none' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, 1000 );
|
||||
|
||||
} );
|
||||
|
||||
var wrapper = codemirror.getWrapperElement();
|
||||
wrapper.addEventListener( 'keydown', function ( event ) {
|
||||
|
||||
event.stopPropagation();
|
||||
|
||||
} );
|
||||
|
||||
//
|
||||
|
||||
var errorDiv = new UI.Div();
|
||||
errorDiv.setPosition( 'absolute' );
|
||||
errorDiv.setDisplay( 'none' );
|
||||
errorDiv.setTop( '8px' );
|
||||
errorDiv.setWidth( '100%' );
|
||||
errorDiv.setTextAlign( 'center' );
|
||||
errorDiv.setZIndex( '3' );
|
||||
container.add( errorDiv );
|
||||
|
||||
var errorText = new UI.Text();
|
||||
errorText.setBackgroundColor( '#f00' );
|
||||
errorText.setColor( '#fff' );
|
||||
errorText.setPadding( '4px' );
|
||||
errorDiv.add( errorText );
|
||||
|
||||
//
|
||||
|
||||
signals.editorCleared.add( function () {
|
||||
|
||||
container.setDisplay( 'none' );
|
||||
|
||||
} );
|
||||
|
||||
signals.effectSelected.add( function ( effect ) {
|
||||
|
||||
container.setDisplay( '' );
|
||||
|
||||
title.setValue( effect.name );
|
||||
|
||||
codemirror.setValue( effect.source );
|
||||
codemirror.clearHistory();
|
||||
|
||||
currentEffect = effect;
|
||||
currentInclude = null;
|
||||
|
||||
} );
|
||||
|
||||
signals.includeSelected.add( function ( include ) {
|
||||
|
||||
container.setDisplay( '' );
|
||||
|
||||
title.setValue( include.name );
|
||||
|
||||
codemirror.setValue( include.source );
|
||||
codemirror.clearHistory();
|
||||
|
||||
currentEffect = null;
|
||||
currentInclude = include;
|
||||
|
||||
} );
|
||||
|
||||
editor.signals.animationSelected.add( function ( animation ) {
|
||||
|
||||
if ( animation === null ) return;
|
||||
|
||||
var effect = animation.effect;
|
||||
|
||||
title.setValue( effect.name );
|
||||
|
||||
codemirror.setValue( effect.source );
|
||||
codemirror.clearHistory();
|
||||
|
||||
currentEffect = effect;
|
||||
currentInclude = null;
|
||||
|
||||
} );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
53
ShadowEditor.Web/src/editor/animation/Config.js
Normal file
53
ShadowEditor.Web/src/editor/animation/Config.js
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Config = function () {
|
||||
|
||||
var name = 'framejs-editor';
|
||||
|
||||
var storage = {};
|
||||
|
||||
if ( window.localStorage[ name ] !== undefined ) {
|
||||
|
||||
var data = JSON.parse( window.localStorage[ name ] );
|
||||
|
||||
for ( var key in data ) {
|
||||
|
||||
storage[ key ] = data[ key ];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
getKey: function ( key ) {
|
||||
|
||||
return storage[ key ];
|
||||
|
||||
},
|
||||
|
||||
setKey: function () { // key, value, key, value ...
|
||||
|
||||
for ( var i = 0, l = arguments.length; i < l; i += 2 ) {
|
||||
|
||||
storage[ arguments[ i ] ] = arguments[ i + 1 ];
|
||||
|
||||
}
|
||||
|
||||
window.localStorage[ name ] = JSON.stringify( storage );
|
||||
|
||||
console.log( '[' + /\d\d\:\d\d\:\d\d/.exec( new Date() )[ 0 ] + ']', 'Saved config to LocalStorage.' );
|
||||
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
|
||||
delete window.localStorage[ name ];
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
133
ShadowEditor.Web/src/editor/animation/Controls.js
Normal file
133
ShadowEditor.Web/src/editor/animation/Controls.js
Normal file
@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Controls = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'controls' );
|
||||
|
||||
var row = new UI.Row();
|
||||
row.setPadding( '6px' );
|
||||
container.add( row );
|
||||
|
||||
var prevButton = new UI.Button();
|
||||
prevButton.setBackground( 'url(files/prev.svg)' );
|
||||
prevButton.setWidth( '20px' );
|
||||
prevButton.setHeight( '20px' );
|
||||
prevButton.setMarginRight( '4px' );
|
||||
prevButton.setVerticalAlign( 'middle' );
|
||||
prevButton.onClick( function () {
|
||||
|
||||
editor.setTime( editor.player.currentTime - 1 );
|
||||
|
||||
} );
|
||||
row.add( prevButton );
|
||||
|
||||
var playButton = new UI.Button();
|
||||
playButton.setBackground( 'url(files/play.svg)' );
|
||||
playButton.setWidth( '20px' );
|
||||
playButton.setHeight( '20px' );
|
||||
playButton.setMarginRight( '4px' );
|
||||
playButton.setVerticalAlign( 'middle' );
|
||||
playButton.onClick( function () {
|
||||
|
||||
editor.player.isPlaying ? editor.stop() : editor.play();
|
||||
|
||||
} );
|
||||
row.add( playButton );
|
||||
|
||||
var nextButton = new UI.Button();
|
||||
nextButton.setBackground( 'url(files/next.svg)' );
|
||||
nextButton.setWidth( '20px' );
|
||||
nextButton.setHeight( '20px' );
|
||||
nextButton.setMarginRight( '4px' );
|
||||
nextButton.setVerticalAlign( 'middle' );
|
||||
nextButton.onClick( function () {
|
||||
|
||||
editor.setTime( editor.player.currentTime + 1 );
|
||||
|
||||
} );
|
||||
row.add( nextButton );
|
||||
|
||||
function ignoreKeys( event ) {
|
||||
|
||||
switch ( event.keyCode ) {
|
||||
|
||||
case 13: case 32: event.preventDefault();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
prevButton.onKeyDown( ignoreKeys );
|
||||
playButton.onKeyDown( ignoreKeys );
|
||||
nextButton.onKeyDown( ignoreKeys );
|
||||
|
||||
var timeText = new UI.Text();
|
||||
timeText.setColor( '#bbb' );
|
||||
timeText.setWidth( '60px' );
|
||||
timeText.setMarginLeft( '10px' );
|
||||
timeText.setValue( '0:00.00' );
|
||||
row.add( timeText );
|
||||
|
||||
function updateTimeText( value ) {
|
||||
|
||||
var minutes = Math.floor( value / 60 );
|
||||
var seconds = value % 60;
|
||||
var padding = seconds < 10 ? '0' : '';
|
||||
|
||||
timeText.setValue( minutes + ':' + padding + seconds.toFixed( 2 ) );
|
||||
|
||||
}
|
||||
|
||||
var playbackRateText = new UI.Text();
|
||||
playbackRateText.setColor( '#999' );
|
||||
playbackRateText.setMarginLeft( '8px' );
|
||||
playbackRateText.setValue( '1.0x' );
|
||||
row.add( playbackRateText );
|
||||
|
||||
function updatePlaybackRateText( value ) {
|
||||
|
||||
playbackRateText.setValue( value.toFixed( 1 ) + 'x' );
|
||||
|
||||
}
|
||||
|
||||
var fullscreenButton = new UI.Button();
|
||||
fullscreenButton.setBackground( 'url(files/fullscreen.svg)' );
|
||||
fullscreenButton.setWidth( '20px' );
|
||||
fullscreenButton.setHeight( '20px' );
|
||||
fullscreenButton.setFloat( 'right' );
|
||||
fullscreenButton.setVerticalAlign( 'middle' );
|
||||
fullscreenButton.onClick( function () {
|
||||
|
||||
editor.signals.fullscreen.dispatch();
|
||||
|
||||
} );
|
||||
row.add( fullscreenButton );
|
||||
|
||||
//
|
||||
|
||||
signals.playingChanged.add( function ( isPlaying ) {
|
||||
|
||||
playButton.setBackground( isPlaying ? 'url(files/pause.svg)' : 'url(files/play.svg)' )
|
||||
|
||||
} );
|
||||
|
||||
signals.playbackRateChanged.add( function ( value ) {
|
||||
|
||||
updatePlaybackRateText( value );
|
||||
|
||||
} );
|
||||
|
||||
signals.timeChanged.add( function ( value ) {
|
||||
|
||||
updateTimeText( value );
|
||||
|
||||
} );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
583
ShadowEditor.Web/src/editor/animation/Editor.js
Normal file
583
ShadowEditor.Web/src/editor/animation/Editor.js
Normal file
@ -0,0 +1,583 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Editor = function () {
|
||||
|
||||
var Signal = signals.Signal;
|
||||
|
||||
this.signals = {
|
||||
|
||||
editorCleared: new Signal(),
|
||||
|
||||
// libraries
|
||||
|
||||
libraryAdded: new Signal(),
|
||||
|
||||
// includes
|
||||
|
||||
includeAdded: new Signal(),
|
||||
includeSelected: new Signal(),
|
||||
includeChanged: new Signal(),
|
||||
includeRemoved: new Signal(),
|
||||
includesCleared: new Signal(),
|
||||
|
||||
// effects
|
||||
|
||||
effectAdded: new Signal(),
|
||||
effectRenamed: new Signal(),
|
||||
effectRemoved: new Signal(),
|
||||
effectSelected: new Signal(),
|
||||
effectCompiled: new Signal(),
|
||||
|
||||
// actions
|
||||
|
||||
fullscreen: new Signal(),
|
||||
exportState: new Signal(),
|
||||
|
||||
// animations
|
||||
|
||||
animationRenamed: new Signal(),
|
||||
animationAdded: new Signal(),
|
||||
animationModified: new Signal(),
|
||||
animationRemoved: new Signal(),
|
||||
animationSelected: new Signal(),
|
||||
|
||||
// curves
|
||||
|
||||
curveAdded: new Signal(),
|
||||
|
||||
// events
|
||||
|
||||
playingChanged: new Signal(),
|
||||
playbackRateChanged: new Signal(),
|
||||
timeChanged: new Signal(),
|
||||
timelineScaled: new Signal(),
|
||||
|
||||
windowResized: new Signal()
|
||||
|
||||
};
|
||||
|
||||
this.config = new Config();
|
||||
|
||||
this.player = new FRAME.Player();
|
||||
this.resources = new FRAME.Resources();
|
||||
|
||||
this.duration = 500;
|
||||
|
||||
this.libraries = [];
|
||||
this.includes = [];
|
||||
this.effects = [];
|
||||
this.timeline = new FRAME.Timeline();
|
||||
|
||||
this.selected = null;
|
||||
|
||||
// signals
|
||||
|
||||
var scope = this;
|
||||
|
||||
this.signals.animationModified.add( function () {
|
||||
|
||||
scope.timeline.reset();
|
||||
scope.timeline.sort();
|
||||
|
||||
try {
|
||||
|
||||
scope.timeline.update( scope.player.currentTime );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
this.signals.effectCompiled.add( function () {
|
||||
|
||||
try {
|
||||
|
||||
scope.timeline.update( scope.player.currentTime );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
this.signals.timeChanged.add( function () {
|
||||
|
||||
try {
|
||||
|
||||
scope.timeline.update( scope.player.currentTime );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
// Animate
|
||||
|
||||
var prevTime = 0;
|
||||
|
||||
function animate( time ) {
|
||||
|
||||
scope.player.tick( time - prevTime );
|
||||
|
||||
if ( scope.player.isPlaying ) {
|
||||
|
||||
scope.signals.timeChanged.dispatch( scope.player.currentTime );
|
||||
|
||||
}
|
||||
|
||||
prevTime = time;
|
||||
|
||||
requestAnimationFrame( animate );
|
||||
|
||||
}
|
||||
|
||||
requestAnimationFrame( animate );
|
||||
|
||||
};
|
||||
|
||||
Editor.prototype = {
|
||||
|
||||
play: function () {
|
||||
|
||||
this.player.play();
|
||||
this.signals.playingChanged.dispatch( true );
|
||||
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
|
||||
this.player.pause();
|
||||
this.signals.playingChanged.dispatch( false );
|
||||
|
||||
},
|
||||
|
||||
speedUp: function () {
|
||||
|
||||
this.player.playbackRate += 0.1;
|
||||
this.signals.playbackRateChanged.dispatch( this.player.playbackRate );
|
||||
|
||||
},
|
||||
|
||||
speedDown: function () {
|
||||
|
||||
this.player.playbackRate -= 0.1;
|
||||
this.signals.playbackRateChanged.dispatch( this.player.playbackRate );
|
||||
|
||||
},
|
||||
|
||||
setTime: function ( time ) {
|
||||
|
||||
// location.hash = time;
|
||||
|
||||
this.player.currentTime = Math.max( 0, time );
|
||||
this.signals.timeChanged.dispatch( this.player.currentTime );
|
||||
|
||||
},
|
||||
|
||||
// libraries
|
||||
|
||||
addLibrary: function ( url, content ) {
|
||||
|
||||
var script = document.createElement( 'script' );
|
||||
script.id = 'library-' + this.libraries.length;
|
||||
script.textContent = content;
|
||||
document.head.appendChild( script );
|
||||
|
||||
this.libraries.push( url );
|
||||
this.signals.libraryAdded.dispatch();
|
||||
|
||||
},
|
||||
|
||||
// includes
|
||||
|
||||
addInclude: function ( name, source ) {
|
||||
|
||||
try {
|
||||
new Function( 'resources', source )( this.resources );
|
||||
} catch ( e ) {
|
||||
console.error( e );
|
||||
}
|
||||
|
||||
this.includes.push( { name: name, source: source } );
|
||||
this.signals.includeAdded.dispatch();
|
||||
|
||||
},
|
||||
|
||||
removeInclude: function ( include ) {
|
||||
|
||||
var index = this.includes.indexOf( include );
|
||||
|
||||
this.includes.splice( index, 1 );
|
||||
this.signals.includeRemoved.dispatch();
|
||||
|
||||
},
|
||||
|
||||
selectInclude: function ( include ) {
|
||||
|
||||
this.signals.includeSelected.dispatch( include );
|
||||
|
||||
},
|
||||
|
||||
reloadIncludes: function () {
|
||||
|
||||
var includes = this.includes;
|
||||
|
||||
this.signals.includesCleared.dispatch();
|
||||
|
||||
for ( var i = 0; i < includes.length; i ++ ) {
|
||||
|
||||
var include = includes[ i ];
|
||||
|
||||
try {
|
||||
new Function( 'resources', include.source )( this.resources );
|
||||
} catch ( e ) {
|
||||
console.error( e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// effects
|
||||
|
||||
addEffect: function ( effect ) {
|
||||
|
||||
this.effects.push( effect );
|
||||
this.signals.effectAdded.dispatch( effect );
|
||||
|
||||
},
|
||||
|
||||
selectEffect: function ( effect ) {
|
||||
|
||||
this.signals.effectSelected.dispatch( effect );
|
||||
|
||||
},
|
||||
|
||||
removeEffect: function ( effect ) {
|
||||
|
||||
var index = this.effects.indexOf( effect );
|
||||
|
||||
if ( index >= 0 ) {
|
||||
|
||||
this.effects.splice( index, 1 );
|
||||
this.signals.effectRemoved.dispatch( effect );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
compileEffect: function ( effect ) {
|
||||
|
||||
try {
|
||||
|
||||
effect.compile( this.resources, this.player );
|
||||
|
||||
} catch ( e ) {
|
||||
|
||||
console.error( e );
|
||||
|
||||
}
|
||||
|
||||
this.signals.effectCompiled.dispatch( effect );
|
||||
|
||||
},
|
||||
|
||||
// Remove any effects that are not bound to any animations.
|
||||
|
||||
cleanEffects: function () {
|
||||
|
||||
var scope = this;
|
||||
var effects = this.effects.slice( 0 );
|
||||
var animations = this.timeline.animations;
|
||||
|
||||
effects.forEach( function ( effect, i ) {
|
||||
|
||||
var bound = false;
|
||||
|
||||
for ( var j = 0; j < animations.length; j++ ) {
|
||||
|
||||
var animation = animations[ j ];
|
||||
|
||||
if ( animation.effect === effect ) {
|
||||
|
||||
bound = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( bound === false ) {
|
||||
|
||||
scope.removeEffect( effect );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
},
|
||||
|
||||
// animations
|
||||
|
||||
addAnimation: function ( animation ) {
|
||||
|
||||
var effect = animation.effect;
|
||||
|
||||
if ( effect.program === null ) {
|
||||
|
||||
this.compileEffect( effect );
|
||||
|
||||
}
|
||||
|
||||
this.timeline.add( animation );
|
||||
this.signals.animationAdded.dispatch( animation );
|
||||
|
||||
},
|
||||
|
||||
selectAnimation: function ( animation ) {
|
||||
|
||||
if ( this.selected === animation ) return;
|
||||
|
||||
this.selected = animation;
|
||||
this.signals.animationSelected.dispatch( animation );
|
||||
|
||||
},
|
||||
|
||||
removeAnimation: function ( animation ) {
|
||||
|
||||
this.timeline.remove( animation );
|
||||
this.signals.animationRemoved.dispatch( animation );
|
||||
|
||||
},
|
||||
|
||||
addCurve: function ( curve ) {
|
||||
|
||||
this.timeline.curves.push( curve );
|
||||
this.signals.curveAdded.dispatch( curve );
|
||||
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
|
||||
this.libraries = [];
|
||||
this.includes = [];
|
||||
this.effects = [];
|
||||
|
||||
while ( this.timeline.animations.length > 0 ) {
|
||||
|
||||
this.removeAnimation( this.timeline.animations[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
this.signals.editorCleared.dispatch();
|
||||
|
||||
},
|
||||
|
||||
fromJSON: function ( json ) {
|
||||
|
||||
function loadFile( url, onLoad ) {
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open( 'GET', url, true );
|
||||
request.addEventListener( 'load', function ( event ) {
|
||||
|
||||
onLoad( event.target.response );
|
||||
|
||||
} );
|
||||
request.send( null );
|
||||
|
||||
}
|
||||
|
||||
function loadLibraries( libraries, onLoad ) {
|
||||
|
||||
var count = 0;
|
||||
|
||||
function loadNext() {
|
||||
|
||||
if ( count === libraries.length ) {
|
||||
|
||||
onLoad();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var url = libraries[ count ++ ];
|
||||
|
||||
loadFile( url, function ( content ) {
|
||||
|
||||
scope.addLibrary( url, content );
|
||||
loadNext();
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
loadNext();
|
||||
|
||||
}
|
||||
|
||||
var scope = this;
|
||||
|
||||
var libraries = json.libraries || [];
|
||||
|
||||
loadLibraries( libraries, function () {
|
||||
|
||||
var includes = json.includes;
|
||||
|
||||
for ( var i = 0, l = includes.length; i < l; i ++ ) {
|
||||
|
||||
var data = includes[ i ];
|
||||
|
||||
var name = data[ 0 ];
|
||||
var source = data[ 1 ];
|
||||
|
||||
if ( Array.isArray( source ) ) source = source.join( '\n' );
|
||||
|
||||
scope.addInclude( name, source );
|
||||
|
||||
}
|
||||
|
||||
var effects = json.effects;
|
||||
|
||||
for ( var i = 0, l = effects.length; i < l; i ++ ) {
|
||||
|
||||
var data = effects[ i ];
|
||||
|
||||
var name = data[ 0 ];
|
||||
var source = data[ 1 ];
|
||||
|
||||
if ( Array.isArray( source ) ) source = source.join( '\n' );
|
||||
|
||||
scope.addEffect( new FRAME.Effect( name, source ) );
|
||||
|
||||
}
|
||||
|
||||
var animations = json.animations;
|
||||
|
||||
for ( var i = 0, l = animations.length; i < l; i ++ ) {
|
||||
|
||||
var data = animations[ i ];
|
||||
|
||||
var animation = new FRAME.Animation(
|
||||
data[ 0 ],
|
||||
data[ 1 ],
|
||||
data[ 2 ],
|
||||
data[ 3 ],
|
||||
scope.effects[ data[ 4 ] ],
|
||||
data[ 5 ]
|
||||
);
|
||||
|
||||
scope.addAnimation( animation );
|
||||
|
||||
}
|
||||
|
||||
scope.setTime( 0 );
|
||||
|
||||
} );
|
||||
|
||||
},
|
||||
|
||||
toJSON: function () {
|
||||
|
||||
var json = {
|
||||
"config": {},
|
||||
"libraries": this.libraries.slice(),
|
||||
"includes": [],
|
||||
"effects": [],
|
||||
// "curves": [],
|
||||
"animations": []
|
||||
};
|
||||
|
||||
/*
|
||||
// curves
|
||||
|
||||
var curves = this.timeline.curves;
|
||||
|
||||
for ( var i = 0, l = curves.length; i < l; i ++ ) {
|
||||
|
||||
var curve = curves[ i ];
|
||||
|
||||
if ( curve instanceof FRAME.Curves.Linear ) {
|
||||
|
||||
json.curves.push( [ 'linear', curve.points ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// includes
|
||||
|
||||
var includes = this.includes;
|
||||
|
||||
for ( var i = 0, l = includes.length; i < l; i ++ ) {
|
||||
|
||||
var include = includes[ i ];
|
||||
|
||||
var name = include.name;
|
||||
var source = include.source;
|
||||
|
||||
json.includes.push( [ name, source.split( '\n' ) ] );
|
||||
|
||||
}
|
||||
|
||||
// effects
|
||||
|
||||
var effects = this.effects;
|
||||
|
||||
for ( var i = 0, l = effects.length; i < l; i ++ ) {
|
||||
|
||||
var effect = effects[ i ];
|
||||
|
||||
var name = effect.name;
|
||||
var source = effect.source;
|
||||
|
||||
json.effects.push( [ name, source.split( '\n' ) ] );
|
||||
|
||||
}
|
||||
|
||||
// animations
|
||||
|
||||
var animations = this.timeline.animations;
|
||||
|
||||
for ( var i = 0, l = animations.length; i < l; i ++ ) {
|
||||
|
||||
var animation = animations[ i ];
|
||||
var effect = animation.effect;
|
||||
|
||||
/*
|
||||
var parameters = {};
|
||||
|
||||
for ( var key in module.parameters ) {
|
||||
|
||||
parameters[ key ] = module.parameters[ key ].value;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
json.animations.push( [
|
||||
animation.name,
|
||||
animation.start,
|
||||
animation.end,
|
||||
animation.layer,
|
||||
this.effects.indexOf( animation.effect ),
|
||||
animation.enabled
|
||||
] );
|
||||
|
||||
}
|
||||
|
||||
return json;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
65
ShadowEditor.Web/src/editor/animation/Menubar.Edit.js
Normal file
65
ShadowEditor.Web/src/editor/animation/Menubar.Edit.js
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Menubar.Edit = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setClass( 'menu' );
|
||||
|
||||
var title = new UI.Panel();
|
||||
title.setClass( 'title' );
|
||||
title.setTextContent( 'Edit' );
|
||||
container.add( title );
|
||||
|
||||
//
|
||||
|
||||
var options = new UI.Panel();
|
||||
options.setClass( 'options' );
|
||||
container.add( options );
|
||||
|
||||
// duplicate
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Duplicate' );
|
||||
option.onClick( function () {
|
||||
|
||||
if ( editor.selected === null ) return;
|
||||
|
||||
var selected = editor.selected;
|
||||
|
||||
var offset = selected.end - selected.start;
|
||||
|
||||
var animation = new FRAME.Animation(
|
||||
selected.name,
|
||||
selected.start + offset,
|
||||
selected.end + offset,
|
||||
selected.layer,
|
||||
selected.effect
|
||||
);
|
||||
|
||||
editor.addAnimation( animation );
|
||||
editor.selectAnimation( animation );
|
||||
|
||||
} );
|
||||
options.add( option );
|
||||
|
||||
// remove
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Remove' );
|
||||
option.onClick( function () {
|
||||
|
||||
if ( editor.selected === null ) return;
|
||||
|
||||
editor.removeAnimation( editor.selected );
|
||||
editor.selectAnimation( null );
|
||||
|
||||
} );
|
||||
options.add( option );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
62
ShadowEditor.Web/src/editor/animation/Menubar.Examples.js
Normal file
62
ShadowEditor.Web/src/editor/animation/Menubar.Examples.js
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Menubar.Examples = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setClass( 'menu' );
|
||||
|
||||
var title = new UI.Panel();
|
||||
title.setClass( 'title' );
|
||||
title.setTextContent( 'Examples' );
|
||||
container.add( title );
|
||||
|
||||
var options = new UI.Panel();
|
||||
options.setClass( 'options' );
|
||||
container.add( options );
|
||||
|
||||
// Examples
|
||||
|
||||
var items = [
|
||||
{ title: 'HTML Colors', file: 'html_colors.json' },
|
||||
{ title: 'HTML Loop', file: 'html_loop.json' },
|
||||
{ title: 'Three.js Cube', file: 'threejs_cube.json' },
|
||||
{ title: 'Three.js Shaders', file: 'threejs_shaders.json' }
|
||||
];
|
||||
|
||||
for ( var i = 0; i < items.length; i ++ ) {
|
||||
|
||||
( function ( i ) {
|
||||
|
||||
var item = items[ i ];
|
||||
|
||||
var option = new UI.Row();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( item.title );
|
||||
option.onClick( function () {
|
||||
|
||||
if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open( 'GET', '../examples/' + item.file, true );
|
||||
request.addEventListener( 'load', function ( event ) {
|
||||
|
||||
editor.clear();
|
||||
editor.fromJSON( JSON.parse( event.target.responseText ) );
|
||||
|
||||
}, false );
|
||||
request.send( null );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
options.add( option );
|
||||
|
||||
} )( i )
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
92
ShadowEditor.Web/src/editor/animation/Menubar.File.js
Normal file
92
ShadowEditor.Web/src/editor/animation/Menubar.File.js
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Menubar.File = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setClass( 'menu' );
|
||||
|
||||
var title = new UI.Panel();
|
||||
title.setClass( 'title' );
|
||||
title.setTextContent( 'File' );
|
||||
container.add( title );
|
||||
|
||||
var options = new UI.Panel();
|
||||
options.setClass( 'options' );
|
||||
container.add( options );
|
||||
|
||||
// New
|
||||
|
||||
var option = new UI.Row();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'New' );
|
||||
option.onClick( function () {
|
||||
|
||||
if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
|
||||
|
||||
editor.clear();
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
options.add( option );
|
||||
|
||||
// import
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Import' );
|
||||
option.onClick( Import );
|
||||
options.add( option );
|
||||
|
||||
var fileInput = document.createElement( 'input' );
|
||||
fileInput.type = 'file';
|
||||
fileInput.addEventListener( 'change', function ( event ) {
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.addEventListener( 'load', function ( event ) {
|
||||
|
||||
editor.clear();
|
||||
editor.fromJSON( JSON.parse( event.target.result ) );
|
||||
|
||||
}, false );
|
||||
|
||||
reader.readAsText( fileInput.files[ 0 ] );
|
||||
|
||||
} );
|
||||
|
||||
function Import () {
|
||||
|
||||
if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) )
|
||||
fileInput.click();
|
||||
|
||||
}
|
||||
|
||||
// export
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Export' );
|
||||
option.onClick( Export );
|
||||
options.add( option );
|
||||
|
||||
signals.exportState.add( Export );
|
||||
|
||||
function Export () {
|
||||
|
||||
var output = JSON.stringify( editor.toJSON(), null, '\t' );
|
||||
|
||||
var blob = new Blob( [ output ], { type: 'text/plain' } );
|
||||
var objectURL = URL.createObjectURL( blob );
|
||||
|
||||
window.open( objectURL, '_blank' );
|
||||
window.focus();
|
||||
|
||||
}
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
41
ShadowEditor.Web/src/editor/animation/Menubar.Help.js
Normal file
41
ShadowEditor.Web/src/editor/animation/Menubar.Help.js
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Menubar.Help = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setClass( 'menu' );
|
||||
|
||||
var title = new UI.Panel();
|
||||
title.setClass( 'title' );
|
||||
title.setTextContent( 'Help' );
|
||||
container.add( title );
|
||||
|
||||
//
|
||||
|
||||
var options = new UI.Panel();
|
||||
options.setClass( 'options' );
|
||||
container.add( options );
|
||||
|
||||
// source code
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Source code' );
|
||||
option.onClick( function () { window.open( 'https://github.com/mrdoob/frame.js/tree/master/editor', '_blank' ) } );
|
||||
options.add( option );
|
||||
|
||||
// about
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'About' );
|
||||
option.onClick( function () { window.open( 'http://github.com/mrdoob/frame.js/', '_blank' ) } );
|
||||
options.add( option );
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
35
ShadowEditor.Web/src/editor/animation/Menubar.View.js
Normal file
35
ShadowEditor.Web/src/editor/animation/Menubar.View.js
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Menubar.View = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setClass( 'menu' );
|
||||
|
||||
var title = new UI.Panel();
|
||||
title.setClass( 'title' );
|
||||
title.setTextContent( 'View' );
|
||||
container.add( title );
|
||||
|
||||
//
|
||||
|
||||
var options = new UI.Panel();
|
||||
options.setClass( 'options' );
|
||||
container.add( options );
|
||||
|
||||
// remove
|
||||
|
||||
var option = new UI.Panel();
|
||||
option.setClass( 'option' );
|
||||
option.setTextContent( 'Fullscreen' );
|
||||
option.onClick( function () {
|
||||
|
||||
editor.signals.fullscreen.dispatch();
|
||||
|
||||
} );
|
||||
options.add( option );
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
17
ShadowEditor.Web/src/editor/animation/Menubar.js
Normal file
17
ShadowEditor.Web/src/editor/animation/Menubar.js
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Menubar = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'menubar' );
|
||||
|
||||
container.add( new Menubar.File( editor ) );
|
||||
container.add( new Menubar.Edit( editor ) );
|
||||
container.add( new Menubar.Examples( editor ) );
|
||||
container.add( new Menubar.Help( editor ) );
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
349
ShadowEditor.Web/src/editor/animation/Sidebar.Animation.js
Normal file
349
ShadowEditor.Web/src/editor/animation/Sidebar.Animation.js
Normal file
@ -0,0 +1,349 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Sidebar.Animation = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'animation' );
|
||||
|
||||
//
|
||||
|
||||
var selected = null;
|
||||
var values;
|
||||
|
||||
function createParameterRow( key, parameter ) {
|
||||
|
||||
if ( parameter === null ) return;
|
||||
|
||||
var parameterRow = new UI.Row();
|
||||
parameterRow.add( new UI.Text( parameter.name ).setWidth( '90px' ) );
|
||||
|
||||
if ( parameter instanceof FRAME.Parameters.Boolean ) {
|
||||
|
||||
var parameterValue = new UI.Checkbox()
|
||||
.setValue( parameter.value )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( parameterValue );
|
||||
|
||||
values[ key ] = parameterValue;
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.Integer ) {
|
||||
|
||||
var parameterValue = new UI.Integer()
|
||||
.setRange( parameter.min, parameter.max )
|
||||
.setValue( parameter.value )
|
||||
.setWidth( '150px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( parameterValue );
|
||||
|
||||
values[ key ] = parameterValue;
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.Float ) {
|
||||
|
||||
var parameterValue = new UI.Number()
|
||||
.setRange( parameter.min, parameter.max )
|
||||
.setValue( parameter.value )
|
||||
.setWidth( '150px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( parameterValue );
|
||||
|
||||
values[ key ] = parameterValue;
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.Vector2 ) {
|
||||
|
||||
var vectorX = new UI.Number()
|
||||
.setValue( parameter.value[ 0 ] )
|
||||
.setWidth( '50px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value[ 0 ] = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
var vectorY = new UI.Number()
|
||||
.setValue( parameter.value[ 1 ] )
|
||||
.setWidth( '50px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value[ 1 ] = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( vectorX );
|
||||
parameterRow.add( vectorY );
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.Vector3 ) {
|
||||
|
||||
var vectorX = new UI.Number()
|
||||
.setValue( parameter.value[ 0 ] )
|
||||
.setWidth( '50px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value[ 0 ] = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
var vectorY = new UI.Number()
|
||||
.setValue( parameter.value[ 1 ] )
|
||||
.setWidth( '50px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value[ 1 ] = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
var vectorZ = new UI.Number()
|
||||
.setValue( parameter.value[ 2 ] )
|
||||
.setWidth( '50px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value[ 2 ] = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( vectorX );
|
||||
parameterRow.add( vectorY );
|
||||
parameterRow.add( vectorZ );
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.String ) {
|
||||
|
||||
var parameterValue = new UI.Input()
|
||||
.setValue( parameter.value )
|
||||
.setWidth( '150px' )
|
||||
.onKeyUp( function () {
|
||||
|
||||
parameter.value = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( parameterValue );
|
||||
|
||||
} else if ( parameter instanceof FRAME.Parameters.Color ) {
|
||||
|
||||
var parameterValue = new UI.Color()
|
||||
.setHexValue( parameter.value )
|
||||
.setWidth( '150px' )
|
||||
.onChange( function () {
|
||||
|
||||
parameter.value = this.getHexValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
|
||||
parameterRow.add( parameterValue );
|
||||
|
||||
}
|
||||
|
||||
return parameterRow;
|
||||
|
||||
}
|
||||
|
||||
function build() {
|
||||
|
||||
container.clear();
|
||||
|
||||
if ( selected === null ) return;
|
||||
|
||||
values = {};
|
||||
|
||||
// Name
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Name' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var animationName = new UI.Input( selected.name )
|
||||
animationName.onChange( function () {
|
||||
|
||||
selected.name = this.getValue();
|
||||
signals.animationRenamed.dispatch( selected );
|
||||
|
||||
} );
|
||||
row.add( animationName );
|
||||
|
||||
// Time
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Time' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var animationStart = new UI.Number( selected.start ).setWidth( '80px' );
|
||||
animationStart.onChange( function () {
|
||||
|
||||
selected.start = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
row.add( animationStart );
|
||||
|
||||
var animationEnd = new UI.Number( selected.end ).setWidth( '80px' );
|
||||
animationEnd.onChange( function () {
|
||||
|
||||
selected.end = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
row.add( animationEnd );
|
||||
|
||||
// Layer
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Layer' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var animationLayer = new UI.Integer( selected.layer ).setWidth( '80px' );
|
||||
animationLayer.onChange( function () {
|
||||
|
||||
selected.layer = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
row.add( animationLayer );
|
||||
|
||||
// Enabled
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Enabled' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var animationEnabled = new UI.Checkbox( selected.enabled )
|
||||
animationEnabled.onChange( function () {
|
||||
|
||||
selected.enabled = this.getValue();
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
} );
|
||||
row.add( animationEnabled );
|
||||
|
||||
//
|
||||
|
||||
container.add( new UI.HorizontalRule().setMargin( '20px 0px' ) );
|
||||
|
||||
//
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Effect' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var effects = editor.effects;
|
||||
var options = {};
|
||||
|
||||
for ( var i = 0; i < effects.length; i ++ ) {
|
||||
|
||||
options[ i ] = effects[ i ].name;
|
||||
|
||||
}
|
||||
|
||||
var effectsSelect = new UI.Select().setWidth( '130px' );
|
||||
effectsSelect.setOptions( options ).setValue( effects.indexOf( selected.effect ) );
|
||||
effectsSelect.onChange( function () {
|
||||
|
||||
editor.timeline.reset();
|
||||
selected.effect = editor.effects[ this.getValue() ];
|
||||
|
||||
signals.animationModified.dispatch( selected );
|
||||
|
||||
build();
|
||||
|
||||
} );
|
||||
row.add( effectsSelect );
|
||||
|
||||
var edit = new UI.Button( 'EDIT' ).setMarginLeft( '8px' );
|
||||
edit.onClick( function () {
|
||||
|
||||
editor.selectEffect( selected.effect );
|
||||
|
||||
} );
|
||||
row.add( edit );
|
||||
|
||||
|
||||
var row = new UI.Row();
|
||||
row.add( new UI.Text( 'Name' ).setWidth( '90px' ) );
|
||||
container.add( row );
|
||||
|
||||
var effectName = new UI.Input( selected.effect.name );
|
||||
effectName.onChange( function () {
|
||||
|
||||
selected.effect.name = this.getValue();
|
||||
signals.effectRenamed.dispatch( selected.effect );
|
||||
|
||||
} );
|
||||
row.add( effectName );
|
||||
|
||||
//
|
||||
|
||||
var parameters = selected.effect.program.parameters;
|
||||
|
||||
for ( var key in parameters ) {
|
||||
|
||||
container.add( createParameterRow( key, parameters[ key ] ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
signals.editorCleared.add( function () {
|
||||
|
||||
selected = null;
|
||||
build();
|
||||
|
||||
} );
|
||||
|
||||
signals.animationSelected.add( function ( animation ) {
|
||||
|
||||
selected = animation;
|
||||
build();
|
||||
|
||||
} );
|
||||
|
||||
signals.effectCompiled.add( build );
|
||||
|
||||
/*
|
||||
signals.timeChanged.add( function () {
|
||||
|
||||
if ( selected !== null ) {
|
||||
|
||||
for ( var key in values ) {
|
||||
|
||||
values[ key ].setValue( selected.module.parameters[ key ].value );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
*/
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
183
ShadowEditor.Web/src/editor/animation/Sidebar.Project.js
Normal file
183
ShadowEditor.Web/src/editor/animation/Sidebar.Project.js
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Sidebar.Project = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'project' );
|
||||
|
||||
// Libraries
|
||||
|
||||
container.add( new UI.Text( 'Libraries' ).setTextTransform( 'uppercase' ) );
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
var libraries = new UI.Select().setMultiple( true ).setWidth( '280px' );
|
||||
container.add( libraries );
|
||||
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
// Effects
|
||||
|
||||
container.add( new UI.Text( 'Effects' ).setTextTransform( 'uppercase' ) );
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
var effects = new UI.Select().setMultiple( true ).setWidth( '280px' ).setMarginBottom( '8px' );
|
||||
container.add( effects );
|
||||
|
||||
var cleanEffects = new UI.Button( 'Clean Effects' );
|
||||
cleanEffects.onClick( function () {
|
||||
|
||||
editor.cleanEffects();
|
||||
|
||||
} );
|
||||
container.add( cleanEffects );
|
||||
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
// Scripts
|
||||
|
||||
container.add( new UI.Text( 'Scripts' ).setTextTransform( 'uppercase' ) );
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
var includesContainer = new UI.Row();
|
||||
container.add( includesContainer );
|
||||
|
||||
var newInclude = new UI.Button( 'New' );
|
||||
newInclude.onClick( function () {
|
||||
|
||||
editor.addInclude( 'Name', '' );
|
||||
|
||||
update();
|
||||
|
||||
} );
|
||||
container.add( newInclude );
|
||||
|
||||
var reload = new UI.Button( 'Reload Scripts' );
|
||||
reload.onClick( function () {
|
||||
|
||||
editor.reloadIncludes();
|
||||
|
||||
var effects = editor.effects;
|
||||
|
||||
for ( var j = 0; j < effects.length; j++ ) {
|
||||
|
||||
var effect = effects[ j ];
|
||||
editor.compileEffect( effect );
|
||||
|
||||
}
|
||||
|
||||
editor.timeline.reset();
|
||||
editor.timeline.update( editor.player.currentTime );
|
||||
|
||||
} );
|
||||
reload.setMarginLeft( '4px' );
|
||||
container.add( reload );
|
||||
|
||||
container.add( new UI.Break(), new UI.Break() );
|
||||
|
||||
//
|
||||
|
||||
function buildInclude( id ) {
|
||||
|
||||
var include = editor.includes[ id ];
|
||||
|
||||
var span = new UI.Span();
|
||||
|
||||
var name = new UI.Input( include.name ).setWidth( '130px' ).setFontSize( '12px' );
|
||||
name.onChange( function () {
|
||||
|
||||
include.name = this.getValue();
|
||||
|
||||
} );
|
||||
span.add( name );
|
||||
|
||||
var edit = new UI.Button( 'Edit' );
|
||||
edit.setMarginLeft( '4px' );
|
||||
edit.onClick( function () {
|
||||
|
||||
editor.selectInclude( include );
|
||||
|
||||
} );
|
||||
span.add( edit );
|
||||
|
||||
var remove = new UI.Button( 'Remove' );
|
||||
remove.setMarginLeft( '4px' );
|
||||
remove.onClick( function () {
|
||||
|
||||
if ( confirm( 'Are you sure?' ) ) {
|
||||
|
||||
editor.removeInclude( include );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
span.add( remove );
|
||||
|
||||
return span;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function update() {
|
||||
|
||||
updateLibraries();
|
||||
updateEffects();
|
||||
updateScripts();
|
||||
|
||||
}
|
||||
|
||||
function updateLibraries() {
|
||||
|
||||
libraries.setOptions( editor.libraries );
|
||||
libraries.dom.size = editor.libraries.length;
|
||||
|
||||
}
|
||||
|
||||
function updateEffects() {
|
||||
|
||||
var names = [];
|
||||
|
||||
for ( var i = 0; i < editor.effects.length; i ++ ) {
|
||||
|
||||
names.push( editor.effects[ i ].name );
|
||||
|
||||
}
|
||||
|
||||
effects.setOptions( names );
|
||||
effects.dom.size = editor.effects.length;
|
||||
|
||||
}
|
||||
|
||||
function updateScripts() {
|
||||
|
||||
includesContainer.clear();
|
||||
|
||||
var includes = editor.includes;
|
||||
|
||||
for ( var i = 0; i < includes.length; i ++ ) {
|
||||
|
||||
includesContainer.add( buildInclude( i ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// signals
|
||||
|
||||
signals.editorCleared.add( update );
|
||||
|
||||
signals.libraryAdded.add( updateLibraries );
|
||||
|
||||
signals.effectAdded.add( updateEffects );
|
||||
signals.effectRemoved.add( updateEffects );
|
||||
|
||||
signals.includeAdded.add( updateScripts );
|
||||
signals.includeRemoved.add( updateScripts );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
12
ShadowEditor.Web/src/editor/animation/Sidebar.Settings.js
Normal file
12
ShadowEditor.Web/src/editor/animation/Sidebar.Settings.js
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Sidebar.Settings = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'settings' );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
80
ShadowEditor.Web/src/editor/animation/Sidebar.js
Normal file
80
ShadowEditor.Web/src/editor/animation/Sidebar.js
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Sidebar = function ( editor ) {
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'sidebar' );
|
||||
|
||||
//
|
||||
|
||||
var animationTab = new UI.Text( 'ANIMATION' ).onClick( onClick );
|
||||
var projectTab = new UI.Text( 'PROJECT' ).onClick( onClick );
|
||||
// var settingsTab = new UI.Text( 'SETTINGS' ).onClick( onClick );
|
||||
|
||||
var tabs = new UI.Div();
|
||||
tabs.setId( 'tabs' );
|
||||
tabs.add( animationTab, projectTab/*, settingsTab*/ );
|
||||
container.add( tabs );
|
||||
|
||||
function onClick( event ) {
|
||||
|
||||
select( event.target.textContent );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var animation = new UI.Span().add(
|
||||
new Sidebar.Animation( editor )
|
||||
);
|
||||
container.add( animation );
|
||||
|
||||
var project = new UI.Span().add(
|
||||
new Sidebar.Project( editor )
|
||||
);
|
||||
container.add( project );
|
||||
/*
|
||||
var settings = new UI.Span().add(
|
||||
new Sidebar.Settings( editor )
|
||||
);
|
||||
container.add( settings );
|
||||
*/
|
||||
|
||||
//
|
||||
|
||||
function select( section ) {
|
||||
|
||||
animationTab.setClass( '' );
|
||||
projectTab.setClass( '' );
|
||||
// settingsTab.setClass( '' );
|
||||
|
||||
animation.setDisplay( 'none' );
|
||||
project.setDisplay( 'none' );
|
||||
// settings.setDisplay( 'none' );
|
||||
|
||||
switch ( section ) {
|
||||
case 'ANIMATION':
|
||||
animationTab.setClass( 'selected' );
|
||||
animation.setDisplay( '' );
|
||||
break;
|
||||
case 'PROJECT':
|
||||
projectTab.setClass( 'selected' );
|
||||
project.setDisplay( '' );
|
||||
break;
|
||||
/*
|
||||
case 'SETTINGS':
|
||||
settingsTab.setClass( 'selected' );
|
||||
settings.setDisplay( '' );
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
select( 'ANIMATION' );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
305
ShadowEditor.Web/src/editor/animation/Timeline.Animations.js
Normal file
305
ShadowEditor.Web/src/editor/animation/Timeline.Animations.js
Normal file
@ -0,0 +1,305 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Timeline.Animations = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setHeight( '100%' );
|
||||
container.setBackground( 'linear-gradient(#444 1px, transparent 1px) 0% 0% / 32px 32px repeat' );
|
||||
|
||||
var scale = 32;
|
||||
|
||||
var Block = ( function ( animation ) {
|
||||
|
||||
var scope = this;
|
||||
|
||||
var dom = document.createElement( 'div' );
|
||||
dom.className = 'block';
|
||||
dom.style.position = 'absolute';
|
||||
dom.style.height = '30px';
|
||||
dom.addEventListener( 'click', function ( event ) {
|
||||
|
||||
editor.selectAnimation( animation );
|
||||
|
||||
} );
|
||||
dom.addEventListener( 'mousedown', function ( event ) {
|
||||
|
||||
var movementX = 0;
|
||||
var movementY = 0;
|
||||
|
||||
function onMouseMove( event ) {
|
||||
|
||||
movementX = event.movementX | event.webkitMovementX | event.mozMovementX | 0;
|
||||
|
||||
animation.start += movementX / scale;
|
||||
animation.end += movementX / scale;
|
||||
|
||||
if ( animation.start < 0 ) {
|
||||
|
||||
var offset = - animation.start;
|
||||
|
||||
animation.start += offset;
|
||||
animation.end += offset;
|
||||
|
||||
}
|
||||
|
||||
movementY += event.movementY | event.webkitMovementY | event.mozMovementY | 0;
|
||||
|
||||
if ( movementY >= 30 ) {
|
||||
|
||||
animation.layer = animation.layer + 1;
|
||||
movementY = 0;
|
||||
|
||||
}
|
||||
|
||||
if ( movementY <= -30 ) {
|
||||
|
||||
animation.layer = Math.max( 0, animation.layer - 1 );
|
||||
movementY = 0;
|
||||
|
||||
}
|
||||
|
||||
signals.animationModified.dispatch( animation );
|
||||
|
||||
}
|
||||
|
||||
function onMouseUp( event ) {
|
||||
|
||||
document.removeEventListener( 'mousemove', onMouseMove );
|
||||
document.removeEventListener( 'mouseup', onMouseUp );
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousemove', onMouseMove, false );
|
||||
document.addEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
}, false );
|
||||
|
||||
var resizeLeft = document.createElement( 'div' );
|
||||
resizeLeft.style.position = 'absolute';
|
||||
resizeLeft.style.width = '6px';
|
||||
resizeLeft.style.height = '30px';
|
||||
resizeLeft.style.cursor = 'w-resize';
|
||||
resizeLeft.addEventListener( 'mousedown', function ( event ) {
|
||||
|
||||
event.stopPropagation();
|
||||
|
||||
var movementX = 0;
|
||||
|
||||
function onMouseMove( event ) {
|
||||
|
||||
movementX = event.movementX | event.webkitMovementX | event.mozMovementX | 0;
|
||||
|
||||
animation.start += movementX / scale;
|
||||
|
||||
signals.animationModified.dispatch( animation );
|
||||
|
||||
}
|
||||
|
||||
function onMouseUp( event ) {
|
||||
|
||||
if ( Math.abs( movementX ) < 2 ) {
|
||||
|
||||
editor.selectAnimation( animation );
|
||||
|
||||
}
|
||||
|
||||
document.removeEventListener( 'mousemove', onMouseMove );
|
||||
document.removeEventListener( 'mouseup', onMouseUp );
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousemove', onMouseMove, false );
|
||||
document.addEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
}, false );
|
||||
dom.appendChild( resizeLeft );
|
||||
|
||||
var name = document.createElement( 'div' );
|
||||
name.className = 'name';
|
||||
dom.appendChild( name );
|
||||
|
||||
var resizeRight = document.createElement( 'div' );
|
||||
resizeRight.style.position = 'absolute';
|
||||
resizeRight.style.right = '0px';
|
||||
resizeRight.style.top = '0px';
|
||||
resizeRight.style.width = '6px';
|
||||
resizeRight.style.height = '30px';
|
||||
resizeRight.style.cursor = 'e-resize';
|
||||
resizeRight.addEventListener( 'mousedown', function ( event ) {
|
||||
|
||||
event.stopPropagation();
|
||||
|
||||
var movementX = 0;
|
||||
|
||||
function onMouseMove( event ) {
|
||||
|
||||
movementX = event.movementX | event.webkitMovementX | event.mozMovementX | 0;
|
||||
|
||||
animation.end += movementX / scale;
|
||||
|
||||
signals.animationModified.dispatch( animation );
|
||||
|
||||
}
|
||||
|
||||
function onMouseUp( event ) {
|
||||
|
||||
if ( Math.abs( movementX ) < 2 ) {
|
||||
|
||||
editor.selectAnimation( animation );
|
||||
|
||||
}
|
||||
|
||||
document.removeEventListener( 'mousemove', onMouseMove );
|
||||
document.removeEventListener( 'mouseup', onMouseUp );
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousemove', onMouseMove, false );
|
||||
document.addEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
}, false );
|
||||
dom.appendChild( resizeRight );
|
||||
|
||||
//
|
||||
|
||||
function getAnimation() {
|
||||
|
||||
return animation;
|
||||
|
||||
}
|
||||
|
||||
function select() {
|
||||
|
||||
dom.classList.add( 'selected' );
|
||||
|
||||
}
|
||||
|
||||
function deselect() {
|
||||
|
||||
dom.classList.remove( 'selected' );
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
animation.enabled === false ? dom.classList.add( 'disabled' ) : dom.classList.remove( 'disabled' );
|
||||
|
||||
dom.style.left = ( animation.start * scale ) + 'px';
|
||||
dom.style.top = ( animation.layer * 32 ) + 'px';
|
||||
dom.style.width = ( ( animation.end - animation.start ) * scale - 2 ) + 'px';
|
||||
|
||||
name.innerHTML = animation.name + ' <span style="opacity:0.5">' + animation.effect.name + '</span>';
|
||||
|
||||
}
|
||||
|
||||
update();
|
||||
|
||||
return {
|
||||
dom: dom,
|
||||
getAnimation: getAnimation,
|
||||
select: select,
|
||||
deselect: deselect,
|
||||
update: update
|
||||
};
|
||||
|
||||
} );
|
||||
|
||||
container.dom.addEventListener( 'dblclick', function ( event ) {
|
||||
|
||||
var start = event.offsetX / scale;
|
||||
var end = start + 2;
|
||||
var layer = Math.floor( event.offsetY / 32 );
|
||||
|
||||
var effect = new FRAME.Effect( 'Effect' );
|
||||
editor.addEffect( effect );
|
||||
|
||||
var animation = new FRAME.Animation( 'Animation', start, end, layer, effect );
|
||||
editor.addAnimation( animation );
|
||||
|
||||
} );
|
||||
|
||||
// signals
|
||||
|
||||
var blocks = {};
|
||||
var selected = null;
|
||||
|
||||
signals.animationAdded.add( function ( animation ) {
|
||||
|
||||
var block = new Block( animation );
|
||||
container.dom.appendChild( block.dom );
|
||||
|
||||
blocks[ animation.id ] = block;
|
||||
|
||||
} );
|
||||
|
||||
signals.animationModified.add( function ( animation ) {
|
||||
|
||||
blocks[ animation.id ].update();
|
||||
|
||||
} );
|
||||
|
||||
signals.animationSelected.add( function ( animation ) {
|
||||
|
||||
if ( blocks[ selected ] !== undefined ) {
|
||||
|
||||
blocks[ selected ].deselect();
|
||||
|
||||
}
|
||||
|
||||
if ( animation === null ) return;
|
||||
|
||||
selected = animation.id;
|
||||
blocks[ selected ].select();
|
||||
|
||||
} );
|
||||
|
||||
signals.animationRemoved.add( function ( animation ) {
|
||||
|
||||
var block = blocks[ animation.id ];
|
||||
container.dom.removeChild( block.dom );
|
||||
|
||||
delete blocks[ animation.id ];
|
||||
|
||||
} );
|
||||
|
||||
signals.timelineScaled.add( function ( value ) {
|
||||
|
||||
scale = value;
|
||||
|
||||
for ( var key in blocks ) {
|
||||
|
||||
blocks[ key ].update();
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
signals.animationRenamed.add( function ( animation ) {
|
||||
|
||||
blocks[ animation.id ].update();
|
||||
|
||||
} );
|
||||
|
||||
signals.effectRenamed.add( function ( effect ) {
|
||||
|
||||
for ( var key in blocks ) {
|
||||
|
||||
var block = blocks[ key ];
|
||||
|
||||
if ( block.getAnimation().effect === effect ) {
|
||||
|
||||
block.update();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
72
ShadowEditor.Web/src/editor/animation/Timeline.Curves.js
Normal file
72
ShadowEditor.Web/src/editor/animation/Timeline.Curves.js
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
Timeline.Curves = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = new UI.Panel();
|
||||
|
||||
var selected = null;
|
||||
var scale = 32;
|
||||
|
||||
var svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
|
||||
svg.style.position = 'fixed';
|
||||
svg.setAttribute( 'width', 2048 );
|
||||
svg.setAttribute( 'height', 128 );
|
||||
container.dom.appendChild( svg );
|
||||
|
||||
var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
|
||||
path.setAttribute( 'style', 'stroke: #444444; stroke-width: 1px; fill: none;' );
|
||||
path.setAttribute( 'd', 'M 0 64 2048 65');
|
||||
svg.appendChild( path );
|
||||
|
||||
var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
|
||||
path.setAttribute( 'style', 'stroke: #00ff00; stroke-width: 1px; fill: none;' );
|
||||
svg.appendChild( path );
|
||||
|
||||
function drawCurve() {
|
||||
|
||||
/*
|
||||
var curve = selected;
|
||||
var drawing = '';
|
||||
|
||||
for ( var i = 0; i <= 2048; i ++ ) {
|
||||
|
||||
curve.update( i / scale );
|
||||
|
||||
drawing += ( i === 0 ? 'M' : 'L' ) + i + ' ' + ( ( 1 - curve.value ) * 64 ) + ' ';
|
||||
|
||||
}
|
||||
|
||||
path.setAttribute( 'd', drawing );
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
// signals
|
||||
|
||||
signals.curveAdded.add( function ( curve ) {
|
||||
|
||||
if ( curve instanceof FRAME.Curves.Saw ) {
|
||||
|
||||
selected = curve;
|
||||
|
||||
drawCurve();
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
signals.timelineScaled.add( function ( value ) {
|
||||
|
||||
scale = value;
|
||||
|
||||
drawCurve();
|
||||
|
||||
} );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
263
ShadowEditor.Web/src/editor/animation/Timeline.js
Normal file
263
ShadowEditor.Web/src/editor/animation/Timeline.js
Normal file
@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Timeline = function ( editor ) {
|
||||
|
||||
var signals = editor.signals;
|
||||
var player = editor.player;
|
||||
|
||||
var container = new UI.Panel();
|
||||
container.setId( 'timeline' );
|
||||
|
||||
// controls
|
||||
|
||||
/*
|
||||
var buttons = new UI.Div();
|
||||
buttons.setPosition( 'absolute' );
|
||||
buttons.setTop( '5px' );
|
||||
buttons.setRight( '5px' );
|
||||
controls.add( buttons );
|
||||
|
||||
var button = new UI.Button();
|
||||
button.setLabel( 'ANIMATIONS' );
|
||||
button.onClick( function () {
|
||||
|
||||
elements.setDisplay( '' );
|
||||
curves.setDisplay( 'none' );
|
||||
|
||||
} );
|
||||
buttons.add( button );
|
||||
|
||||
var button = new UI.Button();
|
||||
button.setLabel( 'CURVES' );
|
||||
button.setMarginLeft( '4px' );
|
||||
button.onClick( function () {
|
||||
|
||||
scroller.style.background = '';
|
||||
|
||||
elements.setDisplay( 'none' );
|
||||
curves.setDisplay( '' );
|
||||
|
||||
} );
|
||||
buttons.add( button );
|
||||
*/
|
||||
|
||||
// timeline
|
||||
|
||||
var keysDown = {};
|
||||
document.addEventListener( 'keydown', function ( event ) { keysDown[ event.keyCode ] = true; } );
|
||||
document.addEventListener( 'keyup', function ( event ) { keysDown[ event.keyCode ] = false; } );
|
||||
|
||||
var scale = 32;
|
||||
var prevScale = scale;
|
||||
|
||||
var timeline = new UI.Panel();
|
||||
timeline.setPosition( 'absolute' );
|
||||
timeline.setTop( '0px' );
|
||||
timeline.setBottom( '0px' );
|
||||
timeline.setWidth( '100%' );
|
||||
timeline.setOverflow( 'hidden' );
|
||||
timeline.dom.addEventListener( 'wheel', function ( event ) {
|
||||
|
||||
if ( event.altKey === true ) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
scale = Math.max( 2, scale + ( event.deltaY / 10 ) );
|
||||
|
||||
signals.timelineScaled.dispatch( scale );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
container.add( timeline );
|
||||
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.height = 32;
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.addEventListener( 'mousedown', function ( event ) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
function onMouseMove( event ) {
|
||||
|
||||
editor.setTime( ( event.offsetX + scroller.scrollLeft ) / scale );
|
||||
|
||||
}
|
||||
|
||||
function onMouseUp( event ) {
|
||||
|
||||
onMouseMove( event );
|
||||
|
||||
document.removeEventListener( 'mousemove', onMouseMove );
|
||||
document.removeEventListener( 'mouseup', onMouseUp );
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousemove', onMouseMove, false );
|
||||
document.addEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
}, false );
|
||||
timeline.dom.appendChild( canvas );
|
||||
|
||||
function updateMarks() {
|
||||
|
||||
canvas.width = scroller.clientWidth;
|
||||
|
||||
var context = canvas.getContext( '2d', { alpha: false } );
|
||||
|
||||
context.fillStyle = '#555';
|
||||
context.fillRect( 0, 0, canvas.width, canvas.height );
|
||||
|
||||
context.strokeStyle = '#888';
|
||||
context.beginPath();
|
||||
|
||||
context.translate( - scroller.scrollLeft, 0 );
|
||||
|
||||
var duration = editor.duration;
|
||||
var width = duration * scale;
|
||||
var scale4 = scale / 4;
|
||||
|
||||
for ( var i = 0.5; i <= width; i += scale ) {
|
||||
|
||||
context.moveTo( i + ( scale4 * 0 ), 18 ); context.lineTo( i + ( scale4 * 0 ), 26 );
|
||||
|
||||
if ( scale > 16 ) context.moveTo( i + ( scale4 * 1 ), 22 ), context.lineTo( i + ( scale4 * 1 ), 26 );
|
||||
if ( scale > 8 ) context.moveTo( i + ( scale4 * 2 ), 22 ), context.lineTo( i + ( scale4 * 2 ), 26 );
|
||||
if ( scale > 16 ) context.moveTo( i + ( scale4 * 3 ), 22 ), context.lineTo( i + ( scale4 * 3 ), 26 );
|
||||
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
|
||||
context.font = '10px Arial';
|
||||
context.fillStyle = '#888'
|
||||
context.textAlign = 'center';
|
||||
|
||||
var step = Math.max( 1, Math.floor( 64 / scale ) );
|
||||
|
||||
for ( var i = 0; i < duration; i += step ) {
|
||||
|
||||
var minute = Math.floor( i / 60 );
|
||||
var second = Math.floor( i % 60 );
|
||||
|
||||
var text = ( minute > 0 ? minute + ':' : '' ) + ( '0' + second ).slice( - 2 );
|
||||
|
||||
context.fillText( text, i * scale, 13 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var scroller = document.createElement( 'div' );
|
||||
scroller.style.position = 'absolute';
|
||||
scroller.style.top = '32px';
|
||||
scroller.style.bottom = '0px';
|
||||
scroller.style.width = '100%';
|
||||
scroller.style.overflow = 'auto';
|
||||
scroller.addEventListener( 'scroll', function ( event ) {
|
||||
|
||||
updateMarks();
|
||||
updateTimeMark();
|
||||
|
||||
}, false );
|
||||
timeline.dom.appendChild( scroller );
|
||||
|
||||
var elements = new Timeline.Animations( editor );
|
||||
scroller.appendChild( elements.dom );
|
||||
|
||||
/*
|
||||
var curves = new Timeline.Curves( editor );
|
||||
curves.setDisplay( 'none' );
|
||||
scroller.appendChild( curves.dom );
|
||||
*/
|
||||
|
||||
function updateContainers() {
|
||||
|
||||
var width = editor.duration * scale;
|
||||
|
||||
elements.setWidth( width + 'px' );
|
||||
// curves.setWidth( width + 'px' );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var loopMark = document.createElement( 'div' );
|
||||
loopMark.style.position = 'absolute';
|
||||
loopMark.style.top = 0;
|
||||
loopMark.style.height = 100 + '%';
|
||||
loopMark.style.width = 0;
|
||||
loopMark.style.background = 'rgba( 255, 255, 255, 0.1 )';
|
||||
loopMark.style.pointerEvents = 'none';
|
||||
loopMark.style.display = 'none';
|
||||
timeline.dom.appendChild( loopMark );
|
||||
|
||||
var timeMark = document.createElement( 'div' );
|
||||
timeMark.style.position = 'absolute';
|
||||
timeMark.style.top = '0px';
|
||||
timeMark.style.left = '-8px';
|
||||
timeMark.style.width = '16px';
|
||||
timeMark.style.height = '100%';
|
||||
timeMark.style.background = 'linear-gradient(90deg, transparent 8px, #f00 8px, #f00 9px, transparent 9px) 0% 0% / 16px 16px repeat-y';
|
||||
timeMark.style.pointerEvents = 'none';
|
||||
timeline.dom.appendChild( timeMark );
|
||||
|
||||
function updateTimeMark() {
|
||||
|
||||
timeMark.style.left = ( player.currentTime * scale ) - scroller.scrollLeft - 8 + 'px';
|
||||
|
||||
// TODO Optimise this
|
||||
|
||||
var loop = player.getLoop();
|
||||
|
||||
if ( Array.isArray( loop ) ) {
|
||||
|
||||
var loopStart = loop[ 0 ] * scale;
|
||||
var loopEnd = loop[ 1 ] * scale;
|
||||
|
||||
loopMark.style.display = '';
|
||||
loopMark.style.left = ( loopStart - scroller.scrollLeft ) + 'px';
|
||||
loopMark.style.width = ( loopEnd - loopStart ) + 'px';
|
||||
|
||||
} else {
|
||||
|
||||
loopMark.style.display = 'none';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// signals
|
||||
|
||||
signals.timeChanged.add( function () {
|
||||
|
||||
updateTimeMark();
|
||||
|
||||
} );
|
||||
|
||||
signals.timelineScaled.add( function ( value ) {
|
||||
|
||||
scale = value;
|
||||
|
||||
scroller.scrollLeft = ( scroller.scrollLeft * value ) / prevScale;
|
||||
|
||||
updateMarks();
|
||||
updateTimeMark();
|
||||
updateContainers();
|
||||
|
||||
prevScale = value;
|
||||
|
||||
} );
|
||||
|
||||
signals.windowResized.add( function () {
|
||||
|
||||
updateMarks();
|
||||
updateContainers();
|
||||
|
||||
} );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
43
ShadowEditor.Web/src/editor/animation/Viewport.js
Normal file
43
ShadowEditor.Web/src/editor/animation/Viewport.js
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var Viewport = function ( editor ) {
|
||||
|
||||
var scope = this;
|
||||
var signals = editor.signals;
|
||||
|
||||
var container = this.container = new UI.Panel();
|
||||
container.setId( 'viewport' );
|
||||
|
||||
editor.resources.set( 'dom', container.dom );
|
||||
|
||||
editor.signals.fullscreen.add( function () {
|
||||
|
||||
var element = container.dom.firstChild;
|
||||
|
||||
if ( element.requestFullscreen ) element.requestFullscreen();
|
||||
if ( element.msRequestFullscreen ) element.msRequestFullscreen();
|
||||
if ( element.mozRequestFullScreen ) element.mozRequestFullScreen();
|
||||
if ( element.webkitRequestFullscreen ) element.webkitRequestFullscreen();
|
||||
|
||||
} );
|
||||
|
||||
function clear () {
|
||||
|
||||
var dom = container.dom;
|
||||
|
||||
while ( dom.children.length ) {
|
||||
|
||||
dom.removeChild( dom.lastChild );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
signals.editorCleared.add( clear );
|
||||
signals.includesCleared.add( clear );
|
||||
|
||||
return container;
|
||||
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user