Browse Source

Merge pull request #724 from LumaDigital/master

Player pause/resume, FPS counter, Q/E swap, directory asset reimport
JoshEngebretson 9 years ago
parent
commit
9440c7885e

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


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

@@ -81,6 +81,12 @@ elements
 	StopButton
 		bitmap stop.png
 
+	PauseButton
+		bitmap pause.png
+
+	StepButton
+		bitmap step.png
+
 	PowerOffButton
 		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
 		id maintoolbar_play
 		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
 		@include definitions>menubutton
 		TBSkinImage: skin: 3DTranslateBitmap

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

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

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

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

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

@@ -30,6 +30,8 @@ class MainToolbar extends Atomic.UIWidget {
     scaleButton: Atomic.UIButton;
     axisButton: Atomic.UIButton;
     playButton: Atomic.UIButton;
+    pauseButton: Atomic.UIButton;
+    stepButton: Atomic.UIButton;
 
     constructor(parent: Atomic.UIWidget) {
 
@@ -45,6 +47,10 @@ class MainToolbar extends Atomic.UIWidget {
 
         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;
 
         parent.addChild(this);
@@ -57,10 +63,22 @@ class MainToolbar extends Atomic.UIWidget {
         this.subscribeToEvent(EditorEvents.PlayerStarted, (data) => {
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             skin.setSkinBg("StopButton");
+            var skin = <Atomic.UISkinImage> this.pauseButton.getWidget("skin_image");
+            skin.setSkinBg("PauseButton");
         });
         this.subscribeToEvent(EditorEvents.PlayerStopped, (data) => {
             var skin = <Atomic.UISkinImage> this.playButton.getWidget("skin_image");
             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");
         });
     }
 
@@ -118,6 +136,14 @@ class MainToolbar extends Atomic.UIWidget {
             } else if (ev.target.id == "maintoolbar_play") {
                 EditorUI.getShortcuts().invokePlayOrStopPlayer();
                 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

@@ -62,6 +62,18 @@ class Shortcuts extends Atomic.ScriptObject {
         }
     }
 
+    invokePauseOrResumePlayer() {
+        if (Atomic.editorMode.isPlayerEnabled()) {
+            this.sendEvent("IPCPlayerPauseResumeRequest");
+        }
+    }
+
+    invokeStepPausedPlayer() {
+        if (Atomic.editorMode.isPlayerEnabled()) {
+            this.sendEvent("IPCPlayerPauseStepRequest");
+        }
+    }
+
     invokeFormatCode() {
 
         var editor = EditorUI.getCurrentResourceEditor();
@@ -192,14 +204,20 @@ class Shortcuts extends Atomic.ScriptObject {
             }
             else if (ev.key == Atomic.KEY_P) {
                 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) {
-                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

@@ -50,6 +50,16 @@ class MainFrameMenu extends Atomic.ScriptObject {
                 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") {
                 EditorUI.getShortcuts().invokePlayOrStopPlayer(true);
                 return true;
@@ -306,6 +316,8 @@ var editItems = {
     "Format Code": ["edit format code", StringID.ShortcutBeautify],
     "-5": null,
     "Play": ["edit play", StringID.ShortcutPlay],
+    "Pause/Resume": ["edit pause", StringID.ShortcutPause],
+    "Step": ["edit step", StringID.ShortcutStep],
     "Debug (C# Project)": ["edit play debug", StringID.ShortcutPlayDebug],
     "-6": null,
     "Snap Settings": ["edit snap settings"]

+ 6 - 0
Script/AtomicEditor/ui/frames/menus/ProjectFrameMenu.ts

@@ -101,6 +101,11 @@ class ProjectFrameMenus extends Atomic.ScriptObject {
                 return true;
             }
 
+            if (refid == "force_reimport_folder") {
+                ToolCore.assetDatabase.reimportAllAssetsInDirectory(path);
+                return true;
+            }
+
         }
 
         return false;
@@ -178,6 +183,7 @@ var assetFolderContextItems = {
     "Create Script": ["create_script", undefined, "ComponentBitmap"],
     "Create Material": ["create_material", undefined, "ComponentBitmap"],
     "Create Scene": ["create_scene", undefined, "ComponentBitmap"],
+    "Force Reimport": ["force_reimport_folder", undefined, ""],
     "-1": null,
     [showInFs]: ["reveal_folder", undefined, ""],
     "-2": null,

+ 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),
     exiting_(false),
     headless_(false),
-    audioPaused_(false)
+    audioPaused_(false),
+    paused_(false),
+    runNextPausedFrame_(false)
 {
     // Register self as a subsystem
     context_->RegisterSubsystem(this);
@@ -157,6 +159,8 @@ Engine::Engine(Context* context) :
     RegisterNavigationLibrary(context_);
 #endif
 
+    SubscribeToEvent(E_PAUSERESUMEREQUESTED, HANDLER(Engine, HandlePauseResumeRequested));
+    SubscribeToEvent(E_PAUSESTEPREQUESTED, HANDLER(Engine, HandlePauseStepRequested));
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(Engine, HandleExitRequested));
 }
 
@@ -453,8 +457,9 @@ void Engine::RunFrame()
 
     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())
         {
@@ -470,6 +475,9 @@ void Engine::RunFrame()
             audio->Play();
             audioPaused_ = false;
         }
+        
+        // Only run one frame when stepping
+        runNextPausedFrame_ = false;
 
         Update();
     }
@@ -499,7 +507,7 @@ Console* Engine::CreateConsole()
     */
 }
 
-DebugHud* Engine::CreateDebugHud()
+SystemUI::DebugHud* Engine::CreateDebugHud()
 {
     return 0;
 
@@ -558,6 +566,23 @@ void Engine::SetNextTimeStep(float seconds)
     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()
 {
 #if defined(IOS)
@@ -937,6 +962,20 @@ const Variant& Engine::GetParameter(const VariantMap& parameters, const String&
     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)
 {
     if (autoExit_)

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

@@ -29,7 +29,11 @@ namespace Atomic
 {
 
 class Console;
+    
+namespace SystemUI
+{
 class DebugHud;
+}
 
 /// Atomic engine. Creates the other subsystems.
 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.)
     Console* CreateConsole();
     /// 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.
     void SetMinFps(int fps);
     /// Set maximum frames per second. The engine will sleep if FPS is higher than this.
@@ -64,6 +68,10 @@ public:
     void SetAutoExit(bool enable);
     /// Override timestep of the next frame. Should be called in between RunFrame() calls.
     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.
     void Exit();
     /// Dump profiling information to the log.
@@ -97,6 +105,12 @@ public:
     /// Return whether engine has been 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.
     bool IsExiting() const { return exiting_; }
 
@@ -123,6 +137,10 @@ public:
     // ATOMIC END
 
 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.
     void HandleExitRequested(StringHash eventType, VariantMap& eventData);
     /// Actually perform the exit actions.
@@ -158,6 +176,10 @@ private:
     bool headless_;
     /// Audio paused flag.
     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),
     workerChannelID_(0)
 {
-    SubscribeToEvent(E_UPDATE, HANDLER(IPC, HandleUpdate));
+    SubscribeToEvent(E_BEGINFRAME, HANDLER(IPC, HandleBeginFrame));
 }
 
 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 (worker_.NotNull())

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

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

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

@@ -217,6 +217,16 @@ EVENT(E_MOUSEMODECHANGED, MouseModeChanged)
     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.
 EVENT(E_EXITREQUESTED, ExitRequested)
 {

+ 42 - 4
Source/Atomic/UI/SystemUI/DebugHud.cpp

@@ -54,12 +54,17 @@ static const char* shadowQualityTexts[] =
     "24bit High"
 };
 
+static const float FPS_UPDATE_INTERVAL = 0.5f;
+
 DebugHud::DebugHud(Context* context) :
     Object(context),
     profilerMaxDepth_(M_MAX_UNSIGNED),
     profilerInterval_(1000),
     useRendererStats_(false),
-    mode_(DEBUGHUD_SHOW_NONE)
+    mode_(DEBUGHUD_SHOW_NONE),
+    fpsTimeSinceUpdate_(FPS_UPDATE_INTERVAL),
+    fpsFramesSinceUpdate_(0),
+    fps_(0)
 {
     SystemUI* ui = GetSubsystem<SystemUI>();
     UIElement* uiRoot = ui->GetRoot();
@@ -92,7 +97,7 @@ DebugHud::~DebugHud()
     profilerText_->Remove();
 }
 
-void DebugHud::Update()
+void DebugHud::Update(float timeStep)
 {
     Graphics* graphics = GetSubsystem<Graphics>();
     Renderer* renderer = GetSubsystem<Renderer>();
@@ -111,6 +116,15 @@ void DebugHud::Update()
 
     if (statsText_->IsVisible())
     {
+        fpsTimeSinceUpdate_ += timeStep;
+        ++fpsFramesSinceUpdate_;
+        if (fpsTimeSinceUpdate_ > FPS_UPDATE_INTERVAL)
+        {
+            fps_ = (int)(fpsFramesSinceUpdate_ / fpsTimeSinceUpdate_);
+            fpsFramesSinceUpdate_ = 0;
+            fpsTimeSinceUpdate_ = 0;
+        }
+
         unsigned primitives, batches;
         if (!useRendererStats_)
         {
@@ -124,7 +138,8 @@ void DebugHud::Update()
         }
 
         String stats;
-        stats.AppendWithFormat("Triangles %u\nBatches %u\nViews %u\nLights %u\nShadowmaps %u\nOccluders %u",
+        stats.AppendWithFormat("FPS %d\nTriangles %u\nBatches %u\nViews %u\nLights %u\nShadowmaps %u\nOccluders %u",
+            fps_,
             primitives,
             batches,
             renderer->GetNumViews(),
@@ -199,6 +214,29 @@ void DebugHud::SetMode(unsigned mode)
     mode_ = mode;
 }
 
+void DebugHud::CycleMode()
+{
+    switch (mode_)
+    {
+    case DEBUGHUD_SHOW_NONE:
+        SetMode(DEBUGHUD_SHOW_STATS);
+        break;
+    case DEBUGHUD_SHOW_STATS:
+        SetMode(DEBUGHUD_SHOW_MODE);
+        break;
+    case DEBUGHUD_SHOW_MODE:
+        SetMode(DEBUGHUD_SHOW_PROFILER);
+        break;
+    case DEBUGHUD_SHOW_PROFILER:
+        SetMode(DEBUGHUD_SHOW_ALL);
+        break;
+    case DEBUGHUD_SHOW_ALL:
+    default:
+        SetMode(DEBUGHUD_SHOW_NONE);
+        break;
+    }
+}
+
 void DebugHud::SetProfilerMaxDepth(unsigned depth)
 {
     profilerMaxDepth_ = depth;
@@ -261,7 +299,7 @@ void DebugHud::HandlePostUpdate(StringHash eventType, VariantMap& eventData)
 {
     using namespace PostUpdate;
 
-    Update();
+    Update(eventData[P_TIMESTEP].GetFloat());
 }
 
 }

+ 10 - 2
Source/Atomic/UI/SystemUI/DebugHud.h

@@ -54,12 +54,14 @@ public:
     /// Destruct.
     ~DebugHud();
 
-    /// Update. Called by HandlePostUpdate().
-    void Update();
+    /// Updates the hud. Called by HandlePostUpdate().
+    void Update(float timeStep);
     /// Set UI elements' style from an XML file.
     void SetDefaultStyle(XMLFile* style);
     /// Set elements to show.
     void SetMode(unsigned mode);
+    /// Cycle through elements
+    void CycleMode();
     /// Set maximum profiler block depth, default unlimited.
     void SetProfilerMaxDepth(unsigned depth);
     /// Set profiler accumulation interval in seconds.
@@ -126,6 +128,12 @@ private:
     bool useRendererStats_;
     /// Current shown-element mode.
     unsigned mode_;
+    /// Time since last fps display update
+    float fpsTimeSinceUpdate_;
+    /// Frames since last fps display update
+    float fpsFramesSinceUpdate_;
+    /// Calculated fps
+    unsigned fps_;
 };
 
 }

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

@@ -83,6 +83,18 @@ EVENT(E_EDITORPLAYERSTARTED, EditorPlayerStarted)
     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
 EVENT(E_EDITORPLAYERSTOPPED, EditorPlayerStopped)
 {

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

@@ -26,6 +26,7 @@
 #include <Atomic/IPC/IPCEvents.h>
 #include <Atomic/IPC/IPCBroker.h>
 
+#include <Atomic/Core/CoreEvents.h>
 #include <Atomic/Input/InputEvents.h>
 
 #include <ToolCore/ToolEnvironment.h>
@@ -50,6 +51,9 @@ EditorMode::EditorMode(Context* context) :
     Object(context)
 {
     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));
 }
 
@@ -167,6 +171,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)
 {
     if (!playerBroker_) return;

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

@@ -56,6 +56,9 @@ private:
     void HandleIPCJSError(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerLog(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);
 
     SharedPtr<IPCBroker> playerBroker_;

+ 2 - 2
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.cpp

@@ -253,12 +253,12 @@ void SceneView3D::MoveCamera(float timeStep)
             SetFocus();
             cameraNode_->Translate(Vector3::RIGHT * MOVE_SPEED * timeStep);
         }
-        if (input->GetKeyDown(KEY_Q))
+        if (input->GetKeyDown(KEY_E))
         {
             SetFocus();
             cameraNode_->Translate(Vector3::UP * MOVE_SPEED * timeStep);
         }
-        if (input->GetKeyDown(KEY_E))
+        if (input->GetKeyDown(KEY_Q))
         {
             SetFocus();
             cameraNode_->Translate(Vector3::DOWN * MOVE_SPEED * timeStep);

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

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

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

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

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

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

+ 17 - 0
Source/ToolCore/Assets/AssetDatabase.cpp

@@ -586,5 +586,22 @@ void AssetDatabase::ReimportAllAssets()
 
 }
 
+void AssetDatabase::ReimportAllAssetsInDirectory(const String& directoryPath)
+{
+    List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
+
+    while (itr != assets_.End())
+    {
+        if ((*itr)->GetPath().StartsWith(directoryPath))
+        {
+            (*itr)->SetDirty(true);
+        }
+        itr++;
+    }
+
+    Scan();
+
+}
+
 
 }

+ 1 - 0
Source/ToolCore/Assets/AssetDatabase.h

@@ -56,6 +56,7 @@ public:
     void Scan();
 
     void ReimportAllAssets();
+    void ReimportAllAssetsInDirectory(const String& directoryPath);
 
     void GetFolderAssets(String folder, PODVector<Asset*>& assets) const;