Browse Source

Added the ability to pause/resume updates on the engine and step one frame at a time. Added Pause/Resume and Step buttons on the editor to pause/resume/step through IPC. NOTE that IPC update has moved to StartFrame so it doesn't get paused.

Matt Benic 9 years ago
parent
commit
9d5a617f58

BIN
Resources/EditorData/AtomicEditor/editor/skin/pause.png


+ 6 - 0
Resources/EditorData/AtomicEditor/editor/skin/skin.tb.txt

@@ -81,6 +81,12 @@ elements
 	StopButton
 	StopButton
 		bitmap stop.png
 		bitmap stop.png
 
 
+	PauseButton
+		bitmap pause.png
+
+	StepButton
+		bitmap step.png
+
 	PowerOffButton
 	PowerOffButton
 		bitmap power_off.png
 		bitmap power_off.png
 
 

BIN
Resources/EditorData/AtomicEditor/editor/skin/step.png


+ 10 - 0
Resources/EditorData/AtomicEditor/editor/ui/maintoolbar.tb.txt

@@ -8,6 +8,16 @@ TBLayout: distribution: gravity, spacing: 4
 		TBSkinImage: skin: PlayButton, id: skin_image
 		TBSkinImage: skin: PlayButton, id: skin_image
 		id maintoolbar_play
 		id maintoolbar_play
 		tooltip Play project
 		tooltip Play project
+	TBButton
+		@include definitions>menubutton
+		TBSkinImage: skin: PauseButton, id: skin_image
+		id maintoolbar_pause
+		tooltip Pause/Resume playing project
+	TBButton
+		@include definitions>menubutton
+		TBSkinImage: skin: StepButton, id: skin_image
+		id maintoolbar_step
+		tooltip Step paused project 1 frame
 	TBButton: toggle-mode: 1
 	TBButton: toggle-mode: 1
 		@include definitions>menubutton
 		@include definitions>menubutton
 		TBSkinImage: skin: 3DTranslateBitmap
 		TBSkinImage: skin: 3DTranslateBitmap

+ 2 - 0
Script/AtomicEditor/editor/EditorEvents.ts

@@ -15,6 +15,8 @@ export interface ModalErrorEvent {
 
 
 export const PlayerStarted = "EditorPlayerStarted";
 export const PlayerStarted = "EditorPlayerStarted";
 export const PlayerStopped = "EditorPlayerStopped";
 export const PlayerStopped = "EditorPlayerStopped";
+export const PlayerPaused = "EditorPlayerPaused";
+export const PlayerResumed = "EditorPlayerResumed";
 export const PlayerLog = "EditorPlayerLog";
 export const PlayerLog = "EditorPlayerLog";
 export interface PlayerLogEvent {
 export interface PlayerLogEvent {
 
 

+ 4 - 0
Script/AtomicEditor/ui/EditorStrings.ts

@@ -21,6 +21,8 @@ export enum StringID {
     ShortcutCloseFile,
     ShortcutCloseFile,
     ShortcutSaveFile,
     ShortcutSaveFile,
     ShortcutPlay,
     ShortcutPlay,
+    ShortcutPause,
+    ShortcutStep,
     ShortcutPlayDebug,
     ShortcutPlayDebug,
     ShortcutBuild,
     ShortcutBuild,
     ShortcutBuildSettings,
     ShortcutBuildSettings,
@@ -74,6 +76,8 @@ export class EditorString {
         lookup[StringID.ShortcutCloseFile] = shortcutKey + "W";
         lookup[StringID.ShortcutCloseFile] = shortcutKey + "W";
 
 
         lookup[StringID.ShortcutPlay] = shortcutKey + "P";
         lookup[StringID.ShortcutPlay] = shortcutKey + "P";
+        lookup[StringID.ShortcutPause] = shortcutKey + "U";
+        lookup[StringID.ShortcutStep] = "⇧" + shortcutKey + "U";
         lookup[StringID.ShortcutPlayDebug] = "⇧" + shortcutKey + "P";
         lookup[StringID.ShortcutPlayDebug] = "⇧" + shortcutKey + "P";
 
 
         lookup[StringID.ShortcutBuild] = shortcutKey + "B";
         lookup[StringID.ShortcutBuild] = shortcutKey + "B";

+ 26 - 0
Script/AtomicEditor/ui/MainToolbar.ts

@@ -15,6 +15,8 @@ class MainToolbar extends Atomic.UIWidget {
     scaleButton: Atomic.UIButton;
     scaleButton: Atomic.UIButton;
     axisButton: Atomic.UIButton;
     axisButton: Atomic.UIButton;
     playButton: Atomic.UIButton;
     playButton: Atomic.UIButton;
+    pauseButton: Atomic.UIButton;
+    stepButton: Atomic.UIButton;
 
 
     constructor(parent: Atomic.UIWidget) {
     constructor(parent: Atomic.UIWidget) {
 
 
@@ -30,6 +32,10 @@ class MainToolbar extends Atomic.UIWidget {
 
 
         this.playButton = <Atomic.UIButton>this.getWidget("maintoolbar_play");
         this.playButton = <Atomic.UIButton>this.getWidget("maintoolbar_play");
 
 
+        this.pauseButton = <Atomic.UIButton>this.getWidget("maintoolbar_pause");
+
+        this.stepButton = <Atomic.UIButton>this.getWidget("maintoolbar_step");
+
         this.translateButton.value = 1;
         this.translateButton.value = 1;
 
 
         parent.addChild(this);
         parent.addChild(this);
@@ -42,10 +48,22 @@ class MainToolbar extends Atomic.UIWidget {
         this.subscribeToEvent(EditorEvents.PlayerStarted, (data) => {
         this.subscribeToEvent(EditorEvents.PlayerStarted, (data) => {
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             skin.setSkinBg("StopButton");
             skin.setSkinBg("StopButton");
+            var skin = <Atomic.UISkinImage> this.pauseButton.getWidget("skin_image");
+            skin.setSkinBg("PauseButton");
         });
         });
         this.subscribeToEvent(EditorEvents.PlayerStopped, (data) => {
         this.subscribeToEvent(EditorEvents.PlayerStopped, (data) => {
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             skin.setSkinBg("PlayButton");
             skin.setSkinBg("PlayButton");
+            var skin = <Atomic.UISkinImage> this.pauseButton.getWidget("skin_image");
+            skin.setSkinBg("PauseButton");
+        });
+        this.subscribeToEvent(EditorEvents.PlayerPaused, (data) => {
+            var skin = <Atomic.UISkinImage> this.pauseButton.getWidget("skin_image");
+            skin.setSkinBg("PlayButton");
+        });
+        this.subscribeToEvent(EditorEvents.PlayerResumed, (data) => {
+            var skin = <Atomic.UISkinImage> this.pauseButton.getWidget("skin_image");
+            skin.setSkinBg("PauseButton");
         });
         });
     }
     }
 
 
@@ -103,6 +121,14 @@ class MainToolbar extends Atomic.UIWidget {
             } else if (ev.target.id == "maintoolbar_play") {
             } else if (ev.target.id == "maintoolbar_play") {
                 EditorUI.getShortcuts().invokePlayOrStopPlayer();
                 EditorUI.getShortcuts().invokePlayOrStopPlayer();
                 return true;
                 return true;
+
+            } else if (ev.target.id == "maintoolbar_pause") {
+                EditorUI.getShortcuts().invokePauseOrResumePlayer();
+                return true;
+
+            } else if (ev.target.id == "maintoolbar_step") {
+                EditorUI.getShortcuts().invokeStepPausedPlayer();
+                return true;
             }
             }
 
 
         }
         }

+ 24 - 6
Script/AtomicEditor/ui/Shortcuts.ts

@@ -47,6 +47,18 @@ class Shortcuts extends Atomic.ScriptObject {
         }
         }
     }
     }
 
 
+    invokePauseOrResumePlayer() {
+        if (Atomic.editorMode.isPlayerEnabled()) {
+            this.sendEvent("IPCPlayerPauseResumeRequest");
+        }
+    }
+
+    invokeStepPausedPlayer() {
+        if (Atomic.editorMode.isPlayerEnabled()) {
+            this.sendEvent("IPCPlayerPauseStepRequest");
+        }
+    }
+
     invokeFormatCode() {
     invokeFormatCode() {
 
 
         var editor = EditorUI.getCurrentResourceEditor();
         var editor = EditorUI.getCurrentResourceEditor();
@@ -177,14 +189,20 @@ class Shortcuts extends Atomic.ScriptObject {
             }
             }
             else if (ev.key == Atomic.KEY_P) {
             else if (ev.key == Atomic.KEY_P) {
                 this.invokePlayOrStopPlayer();
                 this.invokePlayOrStopPlayer();
-                //if shift is pressed
-            } else if (ev.qualifiers & Atomic.QUAL_SHIFT) {
-                if (ev.key == Atomic.KEY_B) {
-                    EditorUI.getModelOps().showBuildSettings();
-                }
             } else if (ev.key == Atomic.KEY_B) {
             } else if (ev.key == Atomic.KEY_B) {
-                EditorUI.getModelOps().showBuild();
+                if (ev.qualifiers & Atomic.QUAL_SHIFT) {
+                    EditorUI.getModelOps().showBuildSettings();
+                } else {
+                    EditorUI.getModelOps().showBuild();
+                }            
             }
             }
+            else if (ev.key == Atomic.KEY_U) {
+                if (ev.qualifiers & Atomic.QUAL_SHIFT) {
+                    this.invokeStepPausedPlayer();
+                } else {
+                    this.invokePauseOrResumePlayer();
+                }
+            } 
 
 
         }
         }
 
 

+ 12 - 0
Script/AtomicEditor/ui/frames/menus/MainFrameMenu.ts

@@ -34,6 +34,16 @@ class MainFrameMenu extends Atomic.ScriptObject {
                 return true;
                 return true;
             }
             }
 
 
+            if (refid == "edit pause") {
+                EditorUI.getShortcuts().invokePauseOrResumePlayer();
+                return true;
+            }
+
+            if (refid == "edit step") {
+                EditorUI.getShortcuts().invokeStepPausedPlayer();
+                return true;
+            }
+
             if (refid == "edit play debug") {
             if (refid == "edit play debug") {
                 EditorUI.getShortcuts().invokePlayOrStopPlayer(true);
                 EditorUI.getShortcuts().invokePlayOrStopPlayer(true);
                 return true;
                 return true;
@@ -278,6 +288,8 @@ var editItems = {
     "Format Code": ["edit format code", StringID.ShortcutBeautify],
     "Format Code": ["edit format code", StringID.ShortcutBeautify],
     "-5": null,
     "-5": null,
     "Play": ["edit play", StringID.ShortcutPlay],
     "Play": ["edit play", StringID.ShortcutPlay],
+    "Pause/Resume": ["edit pause", StringID.ShortcutPause],
+    "Step": ["edit step", StringID.ShortcutStep],
     "Debug (C# Project)": ["edit play debug", StringID.ShortcutPlayDebug],
     "Debug (C# Project)": ["edit play debug", StringID.ShortcutPlayDebug],
     "-6": null,
     "-6": null,
     "Snap Settings": ["edit snap settings"]
     "Snap Settings": ["edit snap settings"]

+ 6 - 0
Source/Atomic/Core/CoreEvents.h

@@ -63,4 +63,10 @@ EVENT(E_ENDFRAME, EndFrame)
 {
 {
 }
 }
 
 
+/// Updating paused or resumed event.
+EVENT(E_UPDATESPAUSEDRESUMED, UpdatesPaused)
+{
+    PARAM(P_PAUSED, Paused);            // bool
+}
+
 }
 }

+ 43 - 4
Source/Atomic/Engine/Engine.cpp

@@ -113,7 +113,9 @@ Engine::Engine(Context* context) :
     initialized_(false),
     initialized_(false),
     exiting_(false),
     exiting_(false),
     headless_(false),
     headless_(false),
-    audioPaused_(false)
+    audioPaused_(false),
+    paused_(false),
+    runNextPausedFrame_(false)
 {
 {
     // Register self as a subsystem
     // Register self as a subsystem
     context_->RegisterSubsystem(this);
     context_->RegisterSubsystem(this);
@@ -157,6 +159,8 @@ Engine::Engine(Context* context) :
     RegisterNavigationLibrary(context_);
     RegisterNavigationLibrary(context_);
 #endif
 #endif
 
 
+    SubscribeToEvent(E_PAUSERESUMEREQUESTED, HANDLER(Engine, HandlePauseResumeRequested));
+    SubscribeToEvent(E_PAUSESTEPREQUESTED, HANDLER(Engine, HandlePauseStepRequested));
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(Engine, HandleExitRequested));
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(Engine, HandleExitRequested));
 }
 }
 
 
@@ -452,8 +456,9 @@ void Engine::RunFrame()
 
 
     time->BeginFrame(timeStep_);
     time->BeginFrame(timeStep_);
 
 
-    // If pause when minimized -mode is in use, stop updates and audio as necessary
-    if (pauseMinimized_ && input->IsMinimized())
+    // If paused, or pause when minimized -mode is in use, stop updates and audio as necessary
+    if ((paused_ && !runNextPausedFrame_) ||
+        (pauseMinimized_ && input->IsMinimized()))
     {
     {
         if (audio->IsPlaying())
         if (audio->IsPlaying())
         {
         {
@@ -469,6 +474,9 @@ void Engine::RunFrame()
             audio->Play();
             audio->Play();
             audioPaused_ = false;
             audioPaused_ = false;
         }
         }
+        
+        // Only run one frame when stepping
+        runNextPausedFrame_ = false;
 
 
         Update();
         Update();
     }
     }
@@ -498,7 +506,7 @@ Console* Engine::CreateConsole()
     */
     */
 }
 }
 
 
-DebugHud* Engine::CreateDebugHud()
+SystemUI::DebugHud* Engine::CreateDebugHud()
 {
 {
     return 0;
     return 0;
 
 
@@ -557,6 +565,23 @@ void Engine::SetNextTimeStep(float seconds)
     timeStep_ = Max(seconds, 0.0f);
     timeStep_ = Max(seconds, 0.0f);
 }
 }
 
 
+void Engine::SetPaused(bool paused)
+{
+    paused_ = paused;
+
+    using namespace UpdatesPaused;
+
+    // Updates paused event
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_PAUSED] = paused_;
+    SendEvent(E_UPDATESPAUSEDRESUMED, eventData);
+}
+
+void Engine::SetRunNextPausedFrame(bool run)
+{
+    runNextPausedFrame_ = run;
+}
+
 void Engine::Exit()
 void Engine::Exit()
 {
 {
 #if defined(IOS)
 #if defined(IOS)
@@ -936,6 +961,20 @@ const Variant& Engine::GetParameter(const VariantMap& parameters, const String&
     return i != parameters.End() ? i->second_ : defaultValue;
     return i != parameters.End() ? i->second_ : defaultValue;
 }
 }
 
 
+
+void Engine::HandlePauseResumeRequested(StringHash eventType, VariantMap& eventData)
+{
+    SetPaused(!IsPaused());
+}
+
+void Engine::HandlePauseStepRequested(StringHash eventType, VariantMap& eventData)
+{
+    if (IsPaused())
+    {
+        SetRunNextPausedFrame(true);
+    }
+}
+
 void Engine::HandleExitRequested(StringHash eventType, VariantMap& eventData)
 void Engine::HandleExitRequested(StringHash eventType, VariantMap& eventData)
 {
 {
     if (autoExit_)
     if (autoExit_)

+ 23 - 1
Source/Atomic/Engine/Engine.h

@@ -29,7 +29,11 @@ namespace Atomic
 {
 {
 
 
 class Console;
 class Console;
+    
+namespace SystemUI
+{
 class DebugHud;
 class DebugHud;
+}
 
 
 /// Atomic engine. Creates the other subsystems.
 /// Atomic engine. Creates the other subsystems.
 class ATOMIC_API Engine : public Object
 class ATOMIC_API Engine : public Object
@@ -49,7 +53,7 @@ public:
     /// Create the console and return it. May return null if engine configuration does not allow creation (headless mode.)
     /// Create the console and return it. May return null if engine configuration does not allow creation (headless mode.)
     Console* CreateConsole();
     Console* CreateConsole();
     /// Create the debug hud.
     /// Create the debug hud.
-    DebugHud* CreateDebugHud();
+    SystemUI::DebugHud* CreateDebugHud();
     /// Set minimum frames per second. If FPS goes lower than this, time will appear to slow down.
     /// Set minimum frames per second. If FPS goes lower than this, time will appear to slow down.
     void SetMinFps(int fps);
     void SetMinFps(int fps);
     /// Set maximum frames per second. The engine will sleep if FPS is higher than this.
     /// Set maximum frames per second. The engine will sleep if FPS is higher than this.
@@ -64,6 +68,10 @@ public:
     void SetAutoExit(bool enable);
     void SetAutoExit(bool enable);
     /// Override timestep of the next frame. Should be called in between RunFrame() calls.
     /// Override timestep of the next frame. Should be called in between RunFrame() calls.
     void SetNextTimeStep(float seconds);
     void SetNextTimeStep(float seconds);
+    /// Set whether the engine is paused.
+    void SetPaused(bool paused);
+    /// Set whether to run the next frame even if paused (for stepping frame by frame)
+    void SetRunNextPausedFrame(bool run);
     /// Close the graphics window and set the exit flag. No-op on iOS, as an iOS application can not legally exit.
     /// Close the graphics window and set the exit flag. No-op on iOS, as an iOS application can not legally exit.
     void Exit();
     void Exit();
     /// Dump profiling information to the log.
     /// Dump profiling information to the log.
@@ -97,6 +105,12 @@ public:
     /// Return whether engine has been initialized.
     /// Return whether engine has been initialized.
     bool IsInitialized() const { return initialized_; }
     bool IsInitialized() const { return initialized_; }
 
 
+    /// Return whether the engine is paused.
+    bool IsPaused() const { return paused_; }
+
+    /// Return whether to run the next frame even if paused (for stepping frame by frame)
+    bool GetRunNextPausedFrame() const { return runNextPausedFrame_; }
+
     /// Return whether exit has been requested.
     /// Return whether exit has been requested.
     bool IsExiting() const { return exiting_; }
     bool IsExiting() const { return exiting_; }
 
 
@@ -123,6 +137,10 @@ public:
     // ATOMIC END
     // ATOMIC END
 
 
 private:
 private:
+    /// Handle exit requested event. Auto-exit if enabled.
+    void HandlePauseResumeRequested(StringHash eventType, VariantMap& eventData);
+    /// Handle exit requested event. Auto-exit if enabled.
+    void HandlePauseStepRequested(StringHash eventType, VariantMap& eventData);
     /// Handle exit requested event. Auto-exit if enabled.
     /// Handle exit requested event. Auto-exit if enabled.
     void HandleExitRequested(StringHash eventType, VariantMap& eventData);
     void HandleExitRequested(StringHash eventType, VariantMap& eventData);
     /// Actually perform the exit actions.
     /// Actually perform the exit actions.
@@ -158,6 +176,10 @@ private:
     bool headless_;
     bool headless_;
     /// Audio paused flag.
     /// Audio paused flag.
     bool audioPaused_;
     bool audioPaused_;
+    /// Engine paused flag
+    bool paused_;
+    /// Whether to run the next frame even if paused (for stepping frame by frame)
+    bool runNextPausedFrame_;
 };
 };
 
 
 }
 }

+ 2 - 2
Source/Atomic/IPC/IPC.cpp

@@ -39,7 +39,7 @@ namespace Atomic
 IPC::IPC(Context* context) : Object(context),
 IPC::IPC(Context* context) : Object(context),
     workerChannelID_(0)
     workerChannelID_(0)
 {
 {
-    SubscribeToEvent(E_UPDATE, HANDLER(IPC, HandleUpdate));
+    SubscribeToEvent(E_BEGINFRAME, HANDLER(IPC, HandleBeginFrame));
 }
 }
 
 
 IPC::~IPC()
 IPC::~IPC()
@@ -102,7 +102,7 @@ void IPC::SendEventToBroker(StringHash eventType, VariantMap& eventData)
     }
     }
 }
 }
 
 
-void IPC::HandleUpdate(StringHash eventType, VariantMap& eventData)
+void IPC::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
 {
 {
     // If we're a worker, if update fails, time to exit
     // If we're a worker, if update fails, time to exit
     if (worker_.NotNull())
     if (worker_.NotNull())

+ 1 - 1
Source/Atomic/IPC/IPC.h

@@ -71,7 +71,7 @@ private:
     unsigned workerChannelID_;
     unsigned workerChannelID_;
 
 
     // processes queued events
     // processes queued events
-    void HandleUpdate(StringHash eventType, VariantMap& eventData);
+    void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
 
 
     mutable Mutex eventMutex_;
     mutable Mutex eventMutex_;
 
 

+ 10 - 0
Source/Atomic/Input/InputEvents.h

@@ -217,6 +217,16 @@ EVENT(E_MOUSEMODECHANGED, MouseModeChanged)
     PARAM(P_MODE, Mode);                    // MouseMode
     PARAM(P_MODE, Mode);                    // MouseMode
 }
 }
 
 
+/// Application pause requested.
+EVENT(E_PAUSERESUMEREQUESTED, PauseResumeRequested)
+{
+}
+
+/// Application step frame while paused requested.
+EVENT(E_PAUSESTEPREQUESTED, PauseStepRequested)
+{
+}
+
 /// Application exit requested.
 /// Application exit requested.
 EVENT(E_EXITREQUESTED, ExitRequested)
 EVENT(E_EXITREQUESTED, ExitRequested)
 {
 {

+ 12 - 0
Source/AtomicEditor/EditorMode/AEEditorEvents.h

@@ -68,6 +68,18 @@ EVENT(E_EDITORPLAYERSTARTED, EditorPlayerStarted)
     PARAM(P_MODE, Mode);    // uint (AEPlayerMode)
     PARAM(P_MODE, Mode);    // uint (AEPlayerMode)
 }
 }
 
 
+// emitted once player has paused
+EVENT(E_EDITORPLAYERPAUSED, EditorPlayerPaused)
+{
+
+}
+
+// emitted once paused player has resumed
+EVENT(E_EDITORPLAYERRESUMED, EditorPlayerResumed)
+{
+
+}
+
 // emitted once play has stopped
 // emitted once play has stopped
 EVENT(E_EDITORPLAYERSTOPPED, EditorPlayerStopped)
 EVENT(E_EDITORPLAYERSTOPPED, EditorPlayerStopped)
 {
 {

+ 29 - 0
Source/AtomicEditor/EditorMode/AEEditorMode.cpp

@@ -11,6 +11,7 @@
 #include <Atomic/IPC/IPCEvents.h>
 #include <Atomic/IPC/IPCEvents.h>
 #include <Atomic/IPC/IPCBroker.h>
 #include <Atomic/IPC/IPCBroker.h>
 
 
+#include <Atomic/Core/CoreEvents.h>
 #include <Atomic/Input/InputEvents.h>
 #include <Atomic/Input/InputEvents.h>
 
 
 #include <ToolCore/ToolEnvironment.h>
 #include <ToolCore/ToolEnvironment.h>
@@ -35,6 +36,9 @@ EditorMode::EditorMode(Context* context) :
     Object(context)
     Object(context)
 {
 {
     SubscribeToEvent(E_IPCWORKERSTART, HANDLER(EditorMode, HandleIPCWorkerStarted));
     SubscribeToEvent(E_IPCWORKERSTART, HANDLER(EditorMode, HandleIPCWorkerStarted));
+    SubscribeToEvent(E_IPCPLAYERPAUSERESUMEREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseResumeRequest));
+    SubscribeToEvent(E_IPCPLAYERUPDATESPAUSEDRESUMED, HANDLER(EditorMode, HandleIPCPlayerUpdatesPausedResumed));
+    SubscribeToEvent(E_IPCPLAYERPAUSESTEPREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseStepRequest));
     SubscribeToEvent(E_IPCPLAYEREXITREQUEST, HANDLER(EditorMode, HandleIPCPlayerExitRequest));
     SubscribeToEvent(E_IPCPLAYEREXITREQUEST, HANDLER(EditorMode, HandleIPCPlayerExitRequest));
 }
 }
 
 
@@ -152,6 +156,31 @@ bool EditorMode::PlayProject(String addArgs, bool debug)
 
 
 }
 }
 
 
+void EditorMode::HandleIPCPlayerPauseResumeRequest(StringHash eventType, VariantMap& eventData)
+{
+    if (!playerBroker_) return;
+    VariantMap noEventData;
+    playerBroker_->PostMessage(E_PAUSERESUMEREQUESTED, noEventData);
+}
+
+void EditorMode::HandleIPCPlayerUpdatesPausedResumed(StringHash eventType, VariantMap& eventData)
+{
+    using namespace UpdatesPaused;
+
+    bool paused = eventData[P_PAUSED].GetBool();
+    if (paused)
+        SendEvent(E_EDITORPLAYERPAUSED);
+    else
+        SendEvent(E_EDITORPLAYERRESUMED);
+}
+
+void EditorMode::HandleIPCPlayerPauseStepRequest(StringHash eventType, VariantMap& eventData)
+{
+    if (!playerBroker_) return;
+    VariantMap noEventData;
+    playerBroker_->PostMessage(E_PAUSESTEPREQUESTED, noEventData);
+}
+
 void EditorMode::HandleIPCPlayerExitRequest(StringHash eventType, VariantMap& eventData)
 void EditorMode::HandleIPCPlayerExitRequest(StringHash eventType, VariantMap& eventData)
 {
 {
     if (!playerBroker_) return;
     if (!playerBroker_) return;

+ 3 - 0
Source/AtomicEditor/EditorMode/AEEditorMode.h

@@ -41,6 +41,9 @@ private:
     void HandleIPCJSError(StringHash eventType, VariantMap& eventData);
     void HandleIPCJSError(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData);
+    void HandleIPCPlayerPauseResumeRequest(StringHash eventType, VariantMap& eventData);
+    void HandleIPCPlayerUpdatesPausedResumed(StringHash eventType, VariantMap& eventData);
+    void HandleIPCPlayerPauseStepRequest(StringHash eventType, VariantMap& eventData);
     void HandleIPCPlayerExitRequest(StringHash eventType, VariantMap& eventData);
     void HandleIPCPlayerExitRequest(StringHash eventType, VariantMap& eventData);
 
 
     SharedPtr<IPCBroker> playerBroker_;
     SharedPtr<IPCBroker> playerBroker_;

+ 15 - 0
Source/AtomicEditor/PlayerMode/AEPlayerEvents.h

@@ -14,6 +14,21 @@ using namespace Atomic;
 namespace AtomicEditor
 namespace AtomicEditor
 {
 {
 
 
+EVENT(E_IPCPLAYERPAUSERESUMEREQUEST, IPCPlayerPauseResumeRequest)
+{
+
+}
+
+EVENT(E_IPCPLAYERUPDATESPAUSEDRESUMED, IPCPlayerUpdatesPausedResumed)
+{
+    PARAM(P_PAUSED, Paused);            // bool
+}
+
+EVENT(E_IPCPLAYERPAUSESTEPREQUEST, IPCPlayerPauseStepRequest)
+{
+
+}
+
 EVENT(E_IPCPLAYEREXITREQUEST, IPCPlayerExitRequest)
 EVENT(E_IPCPLAYEREXITREQUEST, IPCPlayerExitRequest)
 {
 {
 
 

+ 7 - 0
Source/AtomicEditor/PlayerMode/AEPlayerMode.cpp

@@ -9,6 +9,7 @@
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/Input/InputEvents.h>
 #include <Atomic/Input/InputEvents.h>
 #include <Atomic/Core/ProcessUtils.h>
 #include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/Core/CoreEvents.h>
 #include <Atomic/Graphics/GraphicsEvents.h>
 #include <Atomic/Graphics/GraphicsEvents.h>
 #include <Atomic/Graphics/Graphics.h>
 #include <Atomic/Graphics/Graphics.h>
 #include <Atomic/Graphics/Camera.h>
 #include <Atomic/Graphics/Camera.h>
@@ -49,6 +50,7 @@ PlayerMode::PlayerMode(Context* context) :
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(PlayerMode, HandleExitRequest));
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(PlayerMode, HandleExitRequest));
     SubscribeToEvent(E_SCREENMODE, HANDLER(PlayerMode, HandlePlayerWindowChanged));
     SubscribeToEvent(E_SCREENMODE, HANDLER(PlayerMode, HandlePlayerWindowChanged));
     SubscribeToEvent(E_WINDOWPOS, HANDLER(PlayerMode, HandlePlayerWindowChanged));
     SubscribeToEvent(E_WINDOWPOS, HANDLER(PlayerMode, HandlePlayerWindowChanged));
+    SubscribeToEvent(E_UPDATESPAUSEDRESUMED, HANDLER(PlayerMode, HandleUpdatesPausedResumed));
 
 
     // BEGIN LICENSE MANAGEMENT
     // BEGIN LICENSE MANAGEMENT
     SubscribeToEvent(E_BEGINVIEWRENDER, HANDLER(PlayerMode, HandleViewRender));
     SubscribeToEvent(E_BEGINVIEWRENDER, HANDLER(PlayerMode, HandleViewRender));
@@ -255,6 +257,11 @@ void PlayerMode::HandlePlayerWindowChanged(StringHash eventType, VariantMap& eve
     ipc_->SendEventToBroker(E_IPCPLAYERWINDOWCHANGED, data);
     ipc_->SendEventToBroker(E_IPCPLAYERWINDOWCHANGED, data);
 }
 }
 
 
+void PlayerMode::HandleUpdatesPausedResumed(StringHash eventType, VariantMap& eventData)
+{
+    ipc_->SendEventToBroker(E_IPCPLAYERUPDATESPAUSEDRESUMED, eventData);
+}
+
 void PlayerMode::HandleExitRequest(StringHash eventType, VariantMap& eventData)
 void PlayerMode::HandleExitRequest(StringHash eventType, VariantMap& eventData)
 {
 {
     UnsubscribeFromEvent(E_LOGMESSAGE);
     UnsubscribeFromEvent(E_LOGMESSAGE);

+ 1 - 0
Source/AtomicEditor/PlayerMode/AEPlayerMode.h

@@ -43,6 +43,7 @@ private:
     void HandleViewRender(StringHash eventType, VariantMap& eventData);
     void HandleViewRender(StringHash eventType, VariantMap& eventData);
     void HandleExitRequest(StringHash eventType, VariantMap& eventData);
     void HandleExitRequest(StringHash eventType, VariantMap& eventData);
     void HandlePlayerWindowChanged(StringHash eventType, VariantMap& eventData);
     void HandlePlayerWindowChanged(StringHash eventType, VariantMap& eventData);
+    void HandleUpdatesPausedResumed(StringHash eventType, VariantMap& eventData);
 
 
 // BEGIN LICENSE MANAGEMENT
 // BEGIN LICENSE MANAGEMENT
     void HandleMessageAck(StringHash eventType, VariantMap& eventData);
     void HandleMessageAck(StringHash eventType, VariantMap& eventData);