import * as React from "react"; import { Observable, Observer } from "babylonjs/Misc/observable"; import { Scene } from "babylonjs/scene"; import { PropertyChangedEvent } from "../../../../propertyChangedEvent"; import { ButtonLineComponent } from "../../../../../sharedUiComponents/lines/buttonLineComponent"; import { LineContainerComponent } from "../../../lineContainerComponent"; import { SliderLineComponent } from "../../../lines/sliderLineComponent"; import { LockObject } from "../../../../../sharedUiComponents/tabs/propertyGrids/lockObject"; import { GlobalState } from "../../../../globalState"; import { Animation } from "babylonjs/Animations/animation"; import { Animatable } from "babylonjs/Animations/animatable"; import { AnimationPropertiesOverride } from "babylonjs/Animations/animationPropertiesOverride"; import { AnimationRange } from "babylonjs/Animations/animationRange"; import { CheckBoxLineComponent } from "../../../../../sharedUiComponents/lines/checkBoxLineComponent"; import { Nullable } from "babylonjs/types"; import { FloatLineComponent } from "../../../lines/floatLineComponent"; import { TextLineComponent } from "../../../../../sharedUiComponents/lines/textLineComponent"; import { IAnimatable } from "babylonjs/Animations/animatable.interface"; // import { AnimationCurveEditorComponent } from "../animations/animationCurveEditorComponent"; // import { PopupComponent } from "../../../../popupComponent"; interface IAnimationGridComponentProps { globalState: GlobalState; animatable: IAnimatable; scene: Scene; lockObject: LockObject; onPropertyChangedObservable?: Observable; } export class AnimationGridComponent extends React.Component { private _animations: Nullable = null; private _ranges: AnimationRange[]; private _mainAnimatable: Nullable; private _onBeforeRenderObserver: Nullable>; private _isPlaying = false; private timelineRef: React.RefObject; // private _isCurveEditorOpen = false; private _animationControl = { from: 0, to: 0, loop: false, }; constructor(props: IAnimationGridComponentProps) { super(props); this.state = { currentFrame: 0 }; const animatableAsAny = this.props.animatable as any; this._ranges = animatableAsAny.getAnimationRanges ? animatableAsAny.getAnimationRanges() : []; if (animatableAsAny.getAnimatables) { const animatables = animatableAsAny.getAnimatables(); this._animations = new Array(); animatables.forEach((animatable: IAnimatable) => { if (animatable.animations) { this._animations!.push(...animatable.animations); } }); if (animatableAsAny.animations) { this._animations!.push(...animatableAsAny.animations); } // Extract from and to if (this._animations && this._animations.length) { this._animations.forEach((animation) => { let keys = animation.getKeys(); if (keys && keys.length > 0) { if (keys[0].frame < this._animationControl.from) { this._animationControl.from = keys[0].frame; } const lastKeyIndex = keys.length - 1; if (keys[lastKeyIndex].frame > this._animationControl.to) { this._animationControl.to = keys[lastKeyIndex].frame; } } }); } } this.timelineRef = React.createRef(); } playOrPause() { const animatable = this.props.animatable; this._isPlaying = this.props.scene.getAllAnimatablesByTarget(animatable).length > 0; if (this._isPlaying) { this.props.scene.stopAnimation(this.props.animatable); this._mainAnimatable = null; } else { this._mainAnimatable = this.props.scene.beginAnimation( this.props.animatable, this._animationControl.from, this._animationControl.to, this._animationControl.loop ); } this.forceUpdate(); } componentDidMount() { this._onBeforeRenderObserver = this.props.scene.onBeforeRenderObservable.add(() => { if (!this._isPlaying || !this._mainAnimatable) { return; } this.setState({ currentFrame: this._mainAnimatable.masterFrame }); }); } componentWillUnmount() { if (this._onBeforeRenderObserver) { this.props.scene.onBeforeRenderObservable.remove(this._onBeforeRenderObserver); this._onBeforeRenderObserver = null; } } onCurrentFrameChange(value: number) { if (!this._mainAnimatable) { return; } this._mainAnimatable.goToFrame(value); this.setState({ currentFrame: value }); } onChangeFromOrTo() { this.playOrPause(); if (this._isPlaying) { this.playOrPause(); } } // onOpenAnimationCurveEditor() { // this._isCurveEditorOpen = true; // } // onCloseAnimationCurveEditor(window: Window | null) { // this._isCurveEditorOpen = false; // if (window !== null) { // window.close(); // } // } render() { const animatable = this.props.animatable; const animatableAsAny = this.props.animatable as any; let animatablesForTarget = this.props.scene.getAllAnimatablesByTarget(animatable); this._isPlaying = animatablesForTarget.length > 0; if (this._isPlaying && !this._mainAnimatable) { this._mainAnimatable = animatablesForTarget[0]; if (this._mainAnimatable) { this._animationControl.from = this._mainAnimatable.fromFrame; this._animationControl.to = this._mainAnimatable.toFrame; this._animationControl.loop = this._mainAnimatable.loopAnimation; } } let animations = animatable.animations; return (
{this._ranges.length > 0 && ( {this._ranges.map((range, i) => { return ( { this._mainAnimatable = null; this.props.scene.beginAnimation(animatable, range.from, range.to, true); }} /> ); })} )} {animations && ( <> {/* this.onOpenAnimationCurveEditor()} /> {animations.map((anim, i) => { return ( "} value={anim.targetProperty} /> ); })} {this._isCurveEditorOpen && ( {}} onClose={(window: Window) => this.onCloseAnimationCurveEditor(window)} > this.playOrPause()} globalState={this.props.globalState} /> )} */} {animations.length > 0 && ( this.onChangeFromOrTo()} /> this.onChangeFromOrTo()} /> (this._animationControl.loop = value)} isSelected={() => this._animationControl.loop} /> {this._isPlaying && ( this.onCurrentFrameChange(value)} /> )} this.playOrPause()} /> {(this._ranges.length > 0 || (this._animations && this._animations.length > 0)) && ( <> { if (value) { animatableAsAny.animationPropertiesOverride = new AnimationPropertiesOverride(); animatableAsAny.animationPropertiesOverride.blendingSpeed = 0.05; } else { animatableAsAny.animationPropertiesOverride = null; } this.forceUpdate(); }} isSelected={() => animatableAsAny.animationPropertiesOverride != null} onValueChanged={() => this.forceUpdate()} /> {animatableAsAny.animationPropertiesOverride != null && (
)} )}
)} )}
); } }