Browse Source

Merge pull request #8224 from toledoal/property-tree

Property tree
David Catuhe 5 years ago
parent
commit
9b7be8df44

+ 1 - 1
dist/preview release/what's new.md

@@ -8,7 +8,7 @@
 - Added HDR texture filtering tools to the sandbox ([Sebavan](https://github.com/sebavan/))
 - Added HDR texture filtering tools to the sandbox ([Sebavan](https://github.com/sebavan/))
 - Reflection probes can now be used to give accurate shading with PBR ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Reflection probes can now be used to give accurate shading with PBR ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Added editing of PBR materials, Post processes and Particle fragment shaders in the node material editor ([Popov72](https://github.com/Popov72))
 - Added editing of PBR materials, Post processes and Particle fragment shaders in the node material editor ([Popov72](https://github.com/Popov72))
-- Added Curve editor to create and view entity's animations in the Inspector ([pixelspace](https://github.com/devpixelspace))
+- Added Curve editor to create and view selected entity's animations in the Inspector ([pixelspace](https://github.com/devpixelspace))
 - Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
 - Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
 - Added support for **thin instances** for faster mesh instances. [Doc](https://doc.babylonjs.com/how_to/how_to_use_thininstances) ([Popov72](https://github.com/Popov72))
 - Added support for **thin instances** for faster mesh instances. [Doc](https://doc.babylonjs.com/how_to/how_to_use_thininstances) ([Popov72](https://github.com/Popov72))
 
 

+ 3 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/anchorSvgPoint.tsx

@@ -8,6 +8,7 @@ interface IAnchorSvgPointProps {
    active: boolean;
    active: boolean;
    type: string;
    type: string;
    index: string;
    index: string;
+   selected: boolean;
 }
 }
 
 
 
 
@@ -20,9 +21,9 @@ export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps>{
         return (
         return (
         <>
         <>
             <svg x={this.props.control.x} y={this.props.control.y} style={{overflow:'visible'}}>
             <svg x={this.props.control.x} y={this.props.control.y} style={{overflow:'visible'}}>
-                <circle type={this.props.type} data-id={this.props.index} className="draggable control-point" cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill={this.props.active ? "blue" : "black"}   />
+                <circle type={this.props.type} data-id={this.props.index} className={`draggable control-point ${this.props.active ? 'active' : ''}`} cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill={this.props.active ? "blue" : "black"}   />
             </svg>
             </svg>
-            <line x1={this.props.anchor.x} y1={this.props.anchor.y} x2={this.props.control.x} y2={this.props.control.y} stroke="green" strokeWidth="0.75" />
+            <line className={`control-point ${this.props.active ? 'active' : ''}`} x1={this.props.anchor.x} y1={this.props.anchor.y} x2={this.props.control.x} y2={this.props.control.y} stroke="green" strokeWidth="0.75" />
         </>
         </>
         )
         )
     }
     }

+ 141 - 10
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -2,7 +2,9 @@ import * as React from "react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { faTimes } from "@fortawesome/free-solid-svg-icons";
 import { faTimes } from "@fortawesome/free-solid-svg-icons";
 import { Animation } from 'babylonjs/Animations/animation';
 import { Animation } from 'babylonjs/Animations/animation';
-import { Vector2 } from 'babylonjs/Maths/math.vector';
+import { Vector2, Vector3, Quaternion } from 'babylonjs/Maths/math.vector';
+import { Size } from 'babylonjs/Maths/math.size';
+import { Color3, Color4 } from 'babylonjs/Maths/math.color';
 import { EasingFunction } from 'babylonjs/Animations/easing';
 import { EasingFunction } from 'babylonjs/Animations/easing';
 import { IAnimationKey } from 'babylonjs/Animations/animationKey';
 import { IAnimationKey } from 'babylonjs/Animations/animationKey';
 import { IKeyframeSvgPoint } from './keyframeSvgPoint';
 import { IKeyframeSvgPoint } from './keyframeSvgPoint';
@@ -138,7 +140,27 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
 
 
     handleValueChange(event: React.ChangeEvent<HTMLInputElement>) {
     handleValueChange(event: React.ChangeEvent<HTMLInputElement>) {
         event.preventDefault();
         event.preventDefault();
-        this.setState({ currentValue: parseFloat(event.target.value) });
+        this.setState({ currentValue: parseFloat(event.target.value) }, () => {
+            let animation = this.state.selected;
+            let keys = animation.getKeys();
+            
+            let isKeyframe = keys.find(k => k.frame === this.state.currentFrame);
+            if (isKeyframe){
+                let updatedKeys = keys.map(k => {
+                    if (k.frame === this.state.currentFrame){
+                        k.value = this.state.currentValue;
+                    }
+                    return k;
+                });
+                this.state.selected.setKeys(updatedKeys);
+                this.selectAnimation(animation);
+            }
+        });        
+    }
+
+    handleFrameChange(event: React.ChangeEvent<HTMLInputElement>) {
+        event.preventDefault();
+        this.changeCurrentFrame(parseInt(event.target.value))
     }
     }
 
 
     handleTypeChange(event: React.ChangeEvent<HTMLSelectElement>) {
     handleTypeChange(event: React.ChangeEvent<HTMLSelectElement>) {
@@ -161,6 +183,7 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
             if (matchTypeTargetProperty.length === 1) {
             if (matchTypeTargetProperty.length === 1) {
                 let match = (this.props.entity as any)[matchTypeTargetProperty[0]];
                 let match = (this.props.entity as any)[matchTypeTargetProperty[0]];
 
 
+                if (match){
                 switch (match.constructor.name) {
                 switch (match.constructor.name) {
                     case "Vector2":
                     case "Vector2":
                         animationDataType === Animation.ANIMATIONTYPE_VECTOR2 ? matched = true : matched = false;
                         animationDataType === Animation.ANIMATIONTYPE_VECTOR2 ? matched = true : matched = false;
@@ -182,10 +205,11 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
                         break;
                         break;
                     default: console.log("not recognized");
                     default: console.log("not recognized");
                         break;
                         break;
+                    }
+                } else {
+                    this.setState({ notification: `The selected entity doesn't have a ${matchTypeTargetProperty[0]} property` });
                 }
                 }
-            }
-
-            if (matchTypeTargetProperty.length > 1) {
+            } else if (matchTypeTargetProperty.length > 1) {
                 let match = (this.props.entity as any)[matchTypeTargetProperty[0]][matchTypeTargetProperty[1]];
                 let match = (this.props.entity as any)[matchTypeTargetProperty[0]][matchTypeTargetProperty[1]];
                 if (typeof match === "number") {
                 if (typeof match === "number") {
                     animationDataType === Animation.ANIMATIONTYPE_FLOAT ? matched = true : matched = false;
                     animationDataType === Animation.ANIMATIONTYPE_FLOAT ? matched = true : matched = false;
@@ -193,25 +217,62 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
             }
             }
 
 
             if (matched) {
             if (matched) {
+
+                let startValue;
+                let endValue;
+                // Default start and end values for new animations
+                switch (animationDataType) {
+                    case Animation.ANIMATIONTYPE_FLOAT:
+                        startValue = 1;
+                        endValue = 1;
+                        break;
+                    case Animation.ANIMATIONTYPE_VECTOR2:
+                        startValue = new Vector2(1,1);
+                        endValue = new Vector2(1,1);
+                        break;
+                    case Animation.ANIMATIONTYPE_VECTOR3:
+                        startValue = new Vector3(1,1,1);
+                        endValue = new Vector3(1,1,1);
+                        break;
+                    case Animation.ANIMATIONTYPE_QUATERNION:
+                        startValue = new Quaternion(1,1,1,1);
+                        endValue = new Quaternion(1,1,1,1);
+                        break;
+                    case Animation.ANIMATIONTYPE_COLOR3:
+                        startValue = new Color3(1,1,1);
+                        endValue = new Color3(1,1,1);
+                        break;
+                    case Animation.ANIMATIONTYPE_COLOR4:
+                        startValue = new Color4(1,1,1,1);
+                        endValue = new Color4(1,1,1,1);
+                        break;
+                    case Animation.ANIMATIONTYPE_SIZE:
+                        startValue = new Size(1,1);
+                        endValue = new Size(1,1);
+                        break;
+                    default: console.log("not recognized");
+                        break;
+                }
+
                 let animation = new Animation(this.state.animationName, this.state.animationTargetProperty, 30, animationDataType);
                 let animation = new Animation(this.state.animationName, this.state.animationTargetProperty, 30, animationDataType);
 
 
                 // Start with two keyframes
                 // Start with two keyframes
                 var keys = [];
                 var keys = [];
                 keys.push({
                 keys.push({
                     frame: 0,
                     frame: 0,
-                    value: 1
+                    value: startValue
                 });
                 });
 
 
                 keys.push({
                 keys.push({
                     frame: 100,
                     frame: 100,
-                    value: 1
+                    value: endValue
                 });
                 });
 
 
                 animation.setKeys(keys);
                 animation.setKeys(keys);
                 (this.props.entity as IAnimatable).animations?.push(animation);
                 (this.props.entity as IAnimatable).animations?.push(animation);
 
 
             } else {
             } else {
-                this.setState({ notification: `The property "${this.state.animationTargetProperty}" if not a "${this.state.animationType}" type` })
+                this.setState({ notification: `The property "${this.state.animationTargetProperty}" is not a "${this.state.animationType}" type` });
             }
             }
 
 
         } else {
         } else {
@@ -768,7 +829,7 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
                         <FontAwesomeIcon icon={faTimes} />
                         <FontAwesomeIcon icon={faTimes} />
                     </div>
                     </div>
                 </div>
                 </div>
-                <GraphActionsBar currentValue={this.state.currentValue} handleValueChange={(e) => this.handleValueChange(e)} addKeyframe={() => this.addKeyframeClick()} removeKeyframe={() => this.removeKeyframeClick()} flatTangent={() => this.setFlatTangent()} />
+                <GraphActionsBar currentValue={this.state.currentValue} currentFrame={this.state.currentFrame} handleFrameChange={(e) => this.handleFrameChange(e)} handleValueChange={(e) => this.handleValueChange(e)} addKeyframe={() => this.addKeyframeClick()} removeKeyframe={() => this.removeKeyframeClick()} flatTangent={() => this.setFlatTangent()} />
                 <div className="content">
                 <div className="content">
 
 
                     <div className="row">
                     <div className="row">
@@ -802,7 +863,77 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
                                 <h2>{this.props.entityName}</h2>
                                 <h2>{this.props.entityName}</h2>
                                 <ul>
                                 <ul>
                                     {this.props.animations && this.props.animations.map((animation, i) => {
                                     {this.props.animations && this.props.animations.map((animation, i) => {
-                                        return <li className={this.state.selected.name === animation.name ? 'active' : ''} key={i} onClick={() => this.selectAnimation(animation)}>{animation.name} <strong>{animation.targetProperty}</strong></li>
+
+                                        let element;
+
+                                        switch(animation.dataType){
+                                            case Animation.ANIMATIONTYPE_FLOAT:
+                                                element = <li className={this.state.selected.name === animation.name ? 'active' : ''} key={i} onClick={() => this.selectAnimation(animation)}>
+                                                    {animation.name} 
+                                                    <strong>{animation.targetProperty}</strong>
+                                                    </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_VECTOR2:
+                                                element = <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                            <ul>
+                                                                <li key={`${i}_x`}>Property <strong>X</strong></li>
+                                                                <li key={`${i}_y`}>Property <strong>Y</strong></li>
+                                                             </ul>
+                                                        </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_VECTOR3:
+                                                element = <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                            <ul>
+                                                                <li key={`${i}_x`}>Property <strong>X</strong></li>
+                                                                <li key={`${i}_y`}>Property <strong>Y</strong></li>
+                                                                <li key={`${i}_z`}>Property <strong>Z</strong></li>
+                                                             </ul>
+                                                        </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_QUATERNION:
+                                                element = <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                <ul>
+                                                    <li key={`${i}_x`}>Property <strong>X</strong></li>
+                                                    <li key={`${i}_y`}>Property <strong>Y</strong></li>
+                                                    <li key={`${i}_z`}>Property <strong>Z</strong></li>
+                                                    <li key={`${i}_w`}>Property <strong>W</strong></li>
+                                                 </ul>
+                                                </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_COLOR3:
+                                                element = <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                            <ul>
+                                                                <li key={`${i}_r`}>Property <strong>R</strong></li>
+                                                                <li key={`${i}_g`}>Property <strong>G</strong></li>
+                                                                <li key={`${i}_b`}>Property <strong>B</strong></li>
+                                                             </ul>
+                                                        </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_COLOR4:
+                                                element = <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                <ul>
+                                                    <li key={`${i}_r`}>Property <strong>R</strong></li>
+                                                    <li key={`${i}_g`}>Property <strong>G</strong></li>
+                                                    <li key={`${i}_b`}>Property <strong>B</strong></li>
+                                                    <li key={`${i}_a`}>Property <strong>A</strong></li>
+                                                 </ul>
+                                                </li>
+                                                break;
+                                            case Animation.ANIMATIONTYPE_SIZE:
+                                                element =  <li className="property" key={i}><p>{animation.targetProperty}</p>
+                                                            <ul>
+                                                                <li key={`${i}_width`}>Property <strong>Width</strong></li>
+                                                                <li key={`${i}_height`}>Property <strong>Height</strong></li>
+                                                             </ul>
+                                                        </li>
+                                                break;
+                                            default: console.log("not recognized");
+                                                element =  null;
+                                                break;
+                                        }
+
+                                        return element;
+                                        
                                     })}
                                     })}
 
 
                                 </ul>
                                 </ul>

+ 21 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/curveEditor.scss

@@ -142,7 +142,17 @@
             ul {
             ul {
                 list-style:none;
                 list-style:none;
                 padding-left: 0px;
                 padding-left: 0px;
+                li.property {
+                    &:before {
+                        content: '';
+                        background: none;
+                    }
+                }
                 li {
                 li {
+                    p {
+                        font-weight: bolder;
+                        font-variant: all-small-caps;
+                    }
                     cursor: pointer;
                     cursor: pointer;
                     &:before {
                     &:before {
                         content: '';
                         content: '';
@@ -170,7 +180,9 @@
                 background-color: rgba(0, 0, 0, 0.3);
                 background-color: rgba(0, 0, 0, 0.3);
                 padding: 10px;
                 padding: 10px;
                 margin-top: 19px;
                 margin-top: 19px;
-                height: 15em;
+                height: 11em;
+                overflow: scroll;
+                overflow-x: hidden;
             }
             }
 
 
             .label-input{
             .label-input{
@@ -218,6 +230,14 @@
                 text {
                 text {
                     fill: #cecece;
                     fill: #cecece;
                 }
                 }
+
+                .control-point {
+                    display: none;
+                }
+
+                .control-point.active {
+                    display: inline;
+                }
             }
             }
 
 
             .playhead-wrapper {
             .playhead-wrapper {

+ 7 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx

@@ -6,8 +6,10 @@ interface IGraphActionsBarProps {
    addKeyframe: () => void;
    addKeyframe: () => void;
    removeKeyframe: () => void;
    removeKeyframe: () => void;
    handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
    handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+   handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
    flatTangent: () => void;
    flatTangent: () => void;
    currentValue: number;
    currentValue: number;
+   currentFrame: number;
 }
 }
 
 
 export class GraphActionsBar extends React.Component<IGraphActionsBarProps>{ 
 export class GraphActionsBar extends React.Component<IGraphActionsBarProps>{ 
@@ -19,8 +21,12 @@ export class GraphActionsBar extends React.Component<IGraphActionsBarProps>{
        return (
        return (
            <div className="actions-wrapper">
            <div className="actions-wrapper">
                <div className="action-input">
                <div className="action-input">
+               <label>Frame</label>
+               <input type="number" value={this.props.currentFrame} onChange={this.props.handleFrameChange} step="1"/>
+               </div>
+               <div className="action-input">
                <label>Value</label>
                <label>Value</label>
-               <input type="number" value={this.props.currentValue.toFixed(3)} onChange={this.props.handleValueChange}/>
+               <input type="number" value={this.props.currentValue.toFixed(3)} onChange={this.props.handleValueChange} step="0.001"/>
                </div>
                </div>
               <ButtonLineComponent label={"Add Keyframe"} onClick={this.props.addKeyframe} />
               <ButtonLineComponent label={"Add Keyframe"} onClick={this.props.addKeyframe} />
               <ButtonLineComponent label={"Remove Keyframe"} onClick={this.props.removeKeyframe} />
               <ButtonLineComponent label={"Remove Keyframe"} onClick={this.props.removeKeyframe} />

+ 2 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/keyframeSvgPoint.tsx

@@ -28,8 +28,8 @@ export class KeyframeSvgPoint extends React.Component<IKeyframeSvgPointProps>{
                 <svg className="draggable" x={this.props.keyframePoint.x} y={this.props.keyframePoint.y} style={{overflow:'visible'}}>
                 <svg className="draggable" x={this.props.keyframePoint.x} y={this.props.keyframePoint.y} style={{overflow:'visible'}}>
                     <circle data-id={this.props.id} className="draggable" cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill="red" />
                     <circle data-id={this.props.id} className="draggable" cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill="red" />
                 </svg>
                 </svg>
-               { this.props.leftControlPoint && <AnchorSvgPoint type="left" index={this.props.id} control={this.props.leftControlPoint} anchor={this.props.keyframePoint} active={false}/>} 
-               { this.props.rightControlPoint &&  <AnchorSvgPoint type="right" index={this.props.id} control={this.props.rightControlPoint} anchor={this.props.keyframePoint} active={false}/>}
+               { this.props.leftControlPoint && <AnchorSvgPoint type="left" index={this.props.id} control={this.props.leftControlPoint} anchor={this.props.keyframePoint} active={false} selected={false}/>} 
+               { this.props.rightControlPoint &&  <AnchorSvgPoint type="right" index={this.props.id} control={this.props.rightControlPoint} anchor={this.props.keyframePoint} active={false} selected={false}/>}
             </>
             </>
         )
         )
     }
     }