David Catuhe 4 年之前
父节点
当前提交
463969b1da

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

@@ -16,6 +16,10 @@
 
 - Added an `OcclusionMaterial` to simplify depth-only rendering of geometry ([rgerd](https://github.com/rgerd))
 
+### Inspector
+
+- Added support for sounds in the inspector ([Deltakosh](https://github.com/deltakosh))
+
 ### GUI
 
 - Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))

+ 1 - 1
inspector/src/components/actionTabs/lines/sliderLineComponent.tsx

@@ -112,7 +112,7 @@ export class SliderLineComponent extends React.Component<ISliderLineComponentPro
                 <div className={this.props.margin ? "label withMargins" : "label"}  title={this.props.label}>
                     {this.props.label}
                 </div>
-                <FloatLineComponent smallUI={true} label="" target={this.state} propertyName="value" min={this.props.minimum} max={this.props.maximum}
+                <FloatLineComponent smallUI={true} label="" target={this.state} digits={this.props.decimalCount === undefined ? 3 : this.props.decimalCount} propertyName="value" min={this.props.minimum} max={this.props.maximum}
                     onEnter={ () => { 
                         var changed = this.prepareDataToRead(this.state.value); this.onChange(changed);
                     }

+ 10 - 0
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -98,6 +98,8 @@ import { Sprite } from 'babylonjs/Sprites/sprite';
 import { TargetedAnimationGridComponent } from './propertyGrids/animations/targetedAnimationPropertyGridComponent';
 import { FollowCamera } from 'babylonjs/Cameras/followCamera';
 import { FollowCameraPropertyGridComponent } from './propertyGrids/cameras/followCameraPropertyGridComponent';
+import { Sound } from 'babylonjs/Audio/sound';
+import { SoundPropertyGridComponent } from './propertyGrids/sounds/soundPropertyGridComponent';
 
 export class PropertyGridTabComponent extends PaneComponent {
     private _timerIntervalId: number;
@@ -144,6 +146,14 @@ export class PropertyGridTabComponent extends PaneComponent {
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
+            if (className === "Sound") {
+                const sound = entity as Sound;
+                return (<SoundPropertyGridComponent sound={sound}
+                    globalState={this.props.globalState}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
             if (className === "Sprite") {
                 const sprite = entity as Sprite;
                 return (<SpritePropertyGridComponent sprite={sprite}

+ 88 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/sounds/soundPropertyGridComponent.tsx

@@ -0,0 +1,88 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { TextLineComponent } from "../../../lines/textLineComponent";
+import { LockObject } from "../lockObject";
+import { GlobalState } from '../../../../globalState';
+import { Sound } from 'babylonjs/Audio/sound';
+import { IExplorerExtensibilityGroup } from 'babylonjs/Debug/debugLayer';
+import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
+import { SliderLineComponent } from '../../../lines/sliderLineComponent';
+import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
+
+interface ISoundPropertyGridComponentProps {
+    globalState: GlobalState;
+    sound: Sound;    
+    extensibilityGroups?: IExplorerExtensibilityGroup[];
+    lockObject: LockObject;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+}
+
+export class SoundPropertyGridComponent extends React.Component<ISoundPropertyGridComponentProps> {
+    constructor(props: ISoundPropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const sound = this.props.sound;
+
+        return (
+            <div className="pane">
+                <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
+                    <TextLineComponent label="Class" value={sound.getClassName()} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={sound} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                    <TextLineComponent label="Status" value={sound.isPaused ? "Paused" : (sound.isPlaying ? "Playing" : "Stopped")}/>
+                    {/* {
+                        postProcess.width &&
+                        <TextLineComponent label="Width" value={postProcess.width.toString()} />
+                    }
+                    {
+                        postProcess.height &&
+                        <TextLineComponent label="Height" value={postProcess.height.toString()} />
+                    }
+                    <CheckBoxLineComponent label="Auto clear" target={postProcess} propertyName="autoClear" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    {
+                        postProcess.clearColor &&
+                        <Color3LineComponent label="Clear color" target={postProcess} propertyName="clearColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    <CheckBoxLineComponent label="Pixel perfect" target={postProcess} propertyName="enablePixelPerfectMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Fullscreen viewport" target={postProcess} propertyName="forceFullscreenViewport" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <SliderLineComponent label="Samples" target={postProcess} propertyName="samples" minimum={1} maximum={8} step={1} decimalCount={0} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        postProcess.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />                       */}
+                </LineContainerComponent>
+                <LineContainerComponent globalState={this.props.globalState} title="COMMANDS">
+                    {
+                        sound.isPlaying &&
+                        <ButtonLineComponent label="Pause" onClick={() => {
+                            sound.pause();
+                            this.forceUpdate();
+                        }} /> 
+                    }
+                    {
+                        !sound.isPlaying &&
+                        <ButtonLineComponent label="Play" onClick={() => {
+                            sound.play();
+                            this.forceUpdate();
+                        }} /> 
+                    }
+                     <SliderLineComponent label="Samples" 
+                        target={sound} directValue={sound.getVolume()} 
+                        onChange={value => {
+                            sound.setVolume(value);
+                            this.forceUpdate();
+                        }}
+                        minimum={0} maximum={5} step={0.1} decimalCount={1} 
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <CheckBoxLineComponent label="Loop" target={sound} propertyName="loop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                      
+               </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 31 - 0
inspector/src/components/sceneExplorer/entities/soundTreeItemComponent.tsx

@@ -0,0 +1,31 @@
+import { IExplorerExtensibilityGroup } from "babylonjs/Debug/debugLayer";
+import { faMusic } from '@fortawesome/free-solid-svg-icons';
+import { TreeItemLabelComponent } from "../treeItemLabelComponent";
+import { ExtensionsComponent } from "../extensionsComponent";
+import * as React from "react";
+import { Sound } from 'babylonjs/Audio/sound';
+
+interface ISoundTreeItemComponentProps {
+    sound: Sound;
+    extensibilityGroups?: IExplorerExtensibilityGroup[];
+    onClick: () => void;
+}
+
+export class SoundTreeItemComponent extends React.Component<ISoundTreeItemComponentProps> {
+    constructor(props: ISoundTreeItemComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const sound = this.props.sound;
+
+        return (
+            <div className="soundTools">
+                <TreeItemLabelComponent label={sound.name} onClick={() => this.props.onClick()} icon={faMusic} color="teal" />
+                {
+                    <ExtensionsComponent target={sound} extensibilityGroups={this.props.extensibilityGroups} />
+                }
+            </div>
+        );
+    }
+}

+ 15 - 0
inspector/src/components/sceneExplorer/sceneExplorer.scss

@@ -372,6 +372,21 @@
             }
         }
 
+        .soundTools {
+            grid-column: 2;
+            width: 100%;
+            display: grid;
+            grid-template-columns: 1fr auto 5px;
+            align-items: center;
+            min-width: 0;
+           
+            .extensions {
+                width: 20px;
+                grid-column: 2;
+            }
+        }
+
+
         .meshTools {
             grid-column: 2;
             width: 100%;

+ 4 - 0
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -439,6 +439,10 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                 {
                     scene.animationGroups.length > 0 &&
                     <TreeItemComponent globalState={this.props.globalState} extensibilityGroups={this.props.extensibilityGroups} selectedEntity={this.state.selectedEntity} items={scene.animationGroups} label="Animation groups" offset={1} filter={this.state.filter} />
+                }                
+                {
+                    scene.mainSoundTrack && scene.mainSoundTrack.soundCollection.length > 0 &&
+                    <TreeItemComponent globalState={this.props.globalState} extensibilityGroups={this.props.extensibilityGroups} selectedEntity={this.state.selectedEntity} items={scene.mainSoundTrack.soundCollection} label="Sounds" offset={1} filter={this.state.filter} />
                 }
             </div>
         );

+ 6 - 0
inspector/src/components/sceneExplorer/treeItemSpecializedComponent.tsx

@@ -37,6 +37,8 @@ import { SpriteManager } from 'babylonjs/Sprites/spriteManager';
 import { SpriteTreeItemComponent } from './entities/spriteTreeItemComponent';
 import { Sprite } from 'babylonjs/Sprites/sprite';
 import { TargetedAnimationItemComponent } from './entities/targetedAnimationTreeItemComponent';
+import { Sound } from 'babylonjs/Audio/sound';
+import { SoundTreeItemComponent } from './entities/soundTreeItemComponent';
 
 
 interface ITreeItemSpecializedComponentProps {
@@ -135,6 +137,10 @@ export class TreeItemSpecializedComponent extends React.Component<ITreeItemSpeci
                 return (<PostProcessItemComponent extensibilityGroups={this.props.extensibilityGroups} postProcess={entity as PostProcess} onClick={() => this.onClick()} />);
             }
 
+            if (className.indexOf("Sound") !== -1) {
+                return (<SoundTreeItemComponent extensibilityGroups={this.props.extensibilityGroups} sound={entity as Sound} onClick={() => this.onClick()} />);
+            }
+
             if (entity._host) {
                 return (<ControlTreeItemComponent extensibilityGroups={this.props.extensibilityGroups} control={entity as Control} onClick={() => this.onClick()} />);
             }

+ 24 - 2
src/Audio/sound.ts

@@ -24,10 +24,24 @@ export class Sound {
      * Does the sound autoplay once loaded.
      */
     public autoplay: boolean = false;
+    
+    private _loop = false;
     /**
      * Does the sound loop after it finishes playing once.
      */
-    public loop: boolean = false;
+    public get loop(): boolean {
+        return this._loop;
+    }
+
+    public set loop(value: boolean) {
+        if (value === this._loop) {
+            return;
+        }
+
+        this._loop = value;
+        this.updateOptions({loop: value});
+    }
+    
     /**
      * Does the sound use a custom attenuation curve to simulate the falloff
      * happening when the source gets further away from the camera.
@@ -165,7 +179,7 @@ export class Sound {
         };
         if (options) {
             this.autoplay = options.autoplay || false;
-            this.loop = options.loop || false;
+            this._loop = options.loop || false;
             // if volume === 0, we need another way to check this option
             if (options.volume !== undefined) {
                 this._volume = options.volume;
@@ -384,6 +398,14 @@ export class Sound {
         return this._isReadyToPlay;
     }
 
+    /**
+     * Get the current class name.
+     * @returns current class name
+     */
+    public getClassName(): string {
+        return "Sound";
+    }
+
     private _soundLoaded(audioData: ArrayBuffer) {
         if (!Engine.audioEngine.audioContext) {
             return;