2
0
Эх сурвалжийг харах

Changed how modal windows work, so that when closing a modal window a proper window behind it is re-activated
Fixed an issue that was causing a crash when light radius was zero

BearishSun 10 жил өмнө
parent
commit
cab0592226

+ 0 - 2
BansheeCore/BansheeCore.vcxproj

@@ -453,7 +453,6 @@
     <ClInclude Include="Include\BsVertexDeclarationRTTI.h" />
     <ClInclude Include="Include\BsTechnique.h" />
     <ClInclude Include="Include\BsViewportRTTI.h" />
-    <ClInclude Include="Include\Win32\BsWin32Window.h" />
     <ClInclude Include="Include\Win32\BsWin32Defs.h" />
     <ClInclude Include="Include\Win32\BsWin32Platform.h" />
     <ClInclude Include="Include\Win32\BsWin32DropTarget.h" />
@@ -570,7 +569,6 @@
     <ClCompile Include="Source\BsMaterialParams.cpp" />
     <ClCompile Include="Source\Win32\BsWin32Platform.cpp" />
     <ClCompile Include="Source\Win32\BsWin32FolderMonitor.cpp" />
-    <ClCompile Include="Source\Win32\BsWin32Window.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 0 - 12
BansheeCore/BansheeCore.vcxproj.filters

@@ -54,9 +54,6 @@
     <Filter Include="Source Files\RTTI">
       <UniqueIdentifier>{dc50e07b-6351-4bc2-8bfa-cc3fc1d26c39}</UniqueIdentifier>
     </Filter>
-    <Filter Include="Header Files\Win32">
-      <UniqueIdentifier>{1d3fe8eb-ec10-4356-90f0-b27f89f01a13}</UniqueIdentifier>
-    </Filter>
     <Filter Include="Header Files\Text">
       <UniqueIdentifier>{1daa1a6e-95c0-4e63-b339-4a884773fa64}</UniqueIdentifier>
     </Filter>
@@ -84,9 +81,6 @@
     <Filter Include="Source Files\Localization">
       <UniqueIdentifier>{f8c05475-0bc9-44d9-9702-985ec016f0ba}</UniqueIdentifier>
     </Filter>
-    <Filter Include="Source Files\Win32">
-      <UniqueIdentifier>{86aae89f-a09f-469d-bc37-60c7decba0cb}</UniqueIdentifier>
-    </Filter>
     <Filter Include="Header Files\Profiling">
       <UniqueIdentifier>{4ecc02bc-09b0-4d03-a3c0-0ebb7f154d3c}</UniqueIdentifier>
     </Filter>
@@ -539,9 +533,6 @@
     <ClInclude Include="Include\BsStringTableRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
-    <ClInclude Include="Include\Win32\BsWin32Window.h">
-      <Filter>Header Files\Win32</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsParamBlocks.h">
       <Filter>Header Files\Renderer</Filter>
     </ClInclude>
@@ -883,9 +874,6 @@
     <ClCompile Include="Source\BsStringTableManager.cpp">
       <Filter>Source Files\Localization</Filter>
     </ClCompile>
-    <ClCompile Include="Source\Win32\BsWin32Window.cpp">
-      <Filter>Source Files\Win32</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsProfilerCPU.cpp">
       <Filter>Source Files\Profiling</Filter>
     </ClCompile>

+ 0 - 8
BansheeCore/Include/BsCommonTypes.h

@@ -343,14 +343,6 @@ namespace BansheeEngine
 		Transparent = 0x1 /**< Signifies that the shader is rendering a transparent object. */
 	};
 
-	/**	Enum that defines possible window border styles. */
-	enum class WindowBorder
-	{
-		Normal,
-		None,
-		Fixed
-	};
-
 	/**	Texture addressing mode, per component. */
 	struct UVWAddressingMode
 	{

+ 0 - 4
BansheeCore/Include/BsCorePrerequisites.h

@@ -66,10 +66,6 @@
  *  Various utility methods and types used by the core layer.
  */
 
-/** @defgroup Platform-Core Platform
- *  Platform specific functionality.
- */
-
 /** @defgroup Application-Core Application
  *  Entry point into the application.
  */

+ 0 - 2
BansheeCore/Include/Win32/BSWin32PlatformData.h

@@ -33,8 +33,6 @@ namespace BansheeEngine
 		Map<const RenderWindowCore*, WindowNonClientAreaData> mNonClientAreas;
 
 		bool mIsTrackingMouse = false;
-		Vector<RenderWindowCore*> mModalWindowStack;
-
 		NativeDropTargetData mDropTargets;
 
 		bool mRequiresStartUp = false;

+ 0 - 6
BansheeCore/Include/Win32/BsWin32Platform.h

@@ -22,12 +22,6 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT Win32Platform : public Platform
 	{
 	public:
-		/**
-		 * Creates a new bitmap usable by various Win32 methods from the provided pixel data. Caller must ensure to call 
-		 * DeleteObject() on the bitmap handle when finished.
-		 */
-		static HBITMAP createBitmap(const PixelData& pixelData, bool premultiplyAlpha);
-
 		/** Main message loop callback that processes messages received from windows. */
 		static LRESULT CALLBACK _win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 	};

+ 264 - 264
BansheeCore/Source/BsRenderWindowManager.cpp

@@ -1,267 +1,267 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsRenderWindowManager.h"
-#include "BsPlatform.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	RenderWindowManager::RenderWindowManager()
-		:mWindowInFocus(nullptr), mNewWindowInFocus(nullptr)
-	{
-		Platform::onMouseLeftWindow.connect(std::bind(&RenderWindowManager::windowMouseLeft, this, _1));
-	}
-
-	RenderWindowManager::~RenderWindowManager()
-	{
-
-	}
-
-	RenderWindowPtr RenderWindowManager::create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
-	{
-		UINT32 id = RenderWindowCoreManager::instance().mNextWindowId.fetch_add(1, std::memory_order_relaxed);
-
-		RenderWindowPtr renderWindow = createImpl(desc, id, parentWindow);
-		renderWindow->_setThisPtr(renderWindow);
-		
-		{
-			BS_LOCK_MUTEX(mWindowMutex);
-
-			mWindows[renderWindow->mWindowId] = renderWindow.get();
-		}
-
-		renderWindow->initialize();
-		
-		return renderWindow;
-	}
-
-	void RenderWindowManager::notifyWindowDestroyed(RenderWindow* window)
-	{
-		{
-			BS_LOCK_MUTEX(mWindowMutex);
-
-			auto iterFind = std::find_if(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), 
-				[&](const MoveOrResizeData& x) { return x.window == window; });
-
-			if(iterFind != mMovedOrResizedWindows.end())
-				mMovedOrResizedWindows.erase(iterFind);
-
-			if (mNewWindowInFocus == window)
-				mNewWindowInFocus = nullptr;
-
-			mWindows.erase(window->mWindowId);
-			mDirtyProperties.erase(window);
-		}
-	}
-
-	void RenderWindowManager::notifyFocusReceived(RenderWindowCore* coreWindow)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		RenderWindow* window = getNonCore(coreWindow);
-		mNewWindowInFocus = window;
-	}
-
-	void RenderWindowManager::notifyFocusLost(RenderWindowCore* coreWindow)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		mNewWindowInFocus = nullptr;
-	}
-
-	void RenderWindowManager::notifyMovedOrResized(RenderWindowCore* coreWindow)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		RenderWindow* window = getNonCore(coreWindow);
-		if (window == nullptr)
-			return;
-
-		auto iterFind = std::find_if(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), 
-			[&](const MoveOrResizeData& x) { return x.window == window; });
-
-		const RenderWindowProperties& props = coreWindow->getProperties();
-		MoveOrResizeData* moveResizeData = nullptr;
-
-		if (iterFind != end(mMovedOrResizedWindows))
-		{
-			moveResizeData = &*iterFind;
-		}
-		else
-		{
-			MoveOrResizeData newEntry;
-			newEntry.window = window;
-
-			mMovedOrResizedWindows.push_back(newEntry);
-			moveResizeData = &mMovedOrResizedWindows.back();
-		}
-		
-		moveResizeData->x = props.getLeft();
-		moveResizeData->y = props.getTop();
-		moveResizeData->width = props.getWidth();
-		moveResizeData->height = props.getHeight();
-	}
-
-	void RenderWindowManager::notifySyncDataDirty(RenderWindowCore* coreWindow)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		RenderWindow* window = getNonCore(coreWindow);
-
-		if (window != nullptr)
-			mDirtyProperties.insert(window);
-	}
-
-	void RenderWindowManager::windowMouseLeft(RenderWindowCore* coreWindow)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		RenderWindow* window = getNonCore(coreWindow);
-		auto iterFind = std::find(begin(mMouseLeftWindows), end(mMouseLeftWindows), window);
-
-		if (iterFind == end(mMouseLeftWindows))
-			mMouseLeftWindows.push_back(window);
-	}
-
-	void RenderWindowManager::_update()
-	{
-		RenderWindow* newWinInFocus = nullptr;
-		Vector<MoveOrResizeData> movedOrResizedWindows;
-		Vector<RenderWindow*> mouseLeftWindows;
-
-		{
-			BS_LOCK_MUTEX(mWindowMutex);
-			newWinInFocus = mNewWindowInFocus;
-
-			for (auto& moveResizeData : mMovedOrResizedWindows)
-			{
-				RenderWindow* window = moveResizeData.window;
-				const RenderWindowProperties& props = window->getProperties();
-
-				// Need to eliminate non-dirty ones because it's possible we already triggered the resize event
-				// if the resize call originated from the sim thread, so we don't trigger it twice.
-
-				bool isDirty = moveResizeData.x != props.getLeft() || moveResizeData.y != props.getTop()
-					|| moveResizeData.width != props.getWidth() || moveResizeData.height != props.getHeight();
-
-				if (isDirty)
-					movedOrResizedWindows.push_back(moveResizeData);
-			}
-
-			mMovedOrResizedWindows.clear();
-
-			mouseLeftWindows = mMouseLeftWindows;
-			mMouseLeftWindows.clear();
-
-			for (auto& dirtyPropertyWindow : mDirtyProperties)
-				dirtyPropertyWindow->syncProperties();
-
-			mDirtyProperties.clear();
-		}
-
-		if(mWindowInFocus != newWinInFocus)
-		{
-			if(mWindowInFocus != nullptr)
-				onFocusLost(*mWindowInFocus);
-
-			if(newWinInFocus != nullptr)
-				onFocusGained(*newWinInFocus);
-
-			mWindowInFocus = newWinInFocus;
-		}
-
-		for (auto& moveResizeData : movedOrResizedWindows)
-		{
-			moveResizeData.window->onResized();
-		}
-
-		if (!onMouseLeftWindow.empty())
-		{
-			for (auto& window : mouseLeftWindows)
-				onMouseLeftWindow(*window);
-		}			
-	}
-
-	Vector<RenderWindow*> RenderWindowManager::getRenderWindows() const
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		Vector<RenderWindow*> windows;
-		for (auto& windowPair : mWindows)
-			windows.push_back(windowPair.second);
-
-		return windows;
-	}
-
-	RenderWindow* RenderWindowManager::getNonCore(const RenderWindowCore* window) const
-	{
-		auto iterFind = mWindows.find(window->mWindowId);
-
-		if (iterFind != mWindows.end())
-			return iterFind->second;
-
-		return nullptr;
-	}
-
-	RenderWindowCoreManager::RenderWindowCoreManager()
-	{
-		mNextWindowId = 0;
-	}
-
-	SPtr<RenderWindowCore> RenderWindowCoreManager::create(RENDER_WINDOW_DESC& desc)
-	{
-		UINT32 id = mNextWindowId.fetch_add(1, std::memory_order_relaxed);
-
-		SPtr<RenderWindowCore> renderWindow = createInternal(desc, id);
-		renderWindow->initialize();
-
-		return renderWindow;
-	}
-
-	void RenderWindowCoreManager::_update()
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		for (auto& dirtyPropertyWindow : mDirtyProperties)
-			dirtyPropertyWindow->syncProperties();
-
-		mDirtyProperties.clear();
-	}
-
-	void RenderWindowCoreManager::windowCreated(RenderWindowCore* window)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		mCreatedWindows.push_back(window);
-	}
-
-	void RenderWindowCoreManager::windowDestroyed(RenderWindowCore* window)
-	{
-		{
-			BS_LOCK_MUTEX(mWindowMutex);
-
-			auto iterFind = std::find(begin(mCreatedWindows), end(mCreatedWindows), window);
-
-			if (iterFind == mCreatedWindows.end())
-				BS_EXCEPT(InternalErrorException, "Trying to destroy a window that is not in the created windows list.");
-
-			mCreatedWindows.erase(iterFind);
-			mDirtyProperties.erase(window);
-		}
-	}
-
-	Vector<RenderWindowCore*> RenderWindowCoreManager::getRenderWindows() const
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		return mCreatedWindows;
-	}
-
-	void RenderWindowCoreManager::notifySyncDataDirty(RenderWindowCore* window)
-	{
-		BS_LOCK_MUTEX(mWindowMutex);
-
-		mDirtyProperties.insert(window);
-	}
+#include "BsRenderWindowManager.h"
+#include "BsPlatform.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	RenderWindowManager::RenderWindowManager()
+		:mWindowInFocus(nullptr), mNewWindowInFocus(nullptr)
+	{
+		Platform::onMouseLeftWindow.connect(std::bind(&RenderWindowManager::windowMouseLeft, this, _1));
+	}
+
+	RenderWindowManager::~RenderWindowManager()
+	{
+
+	}
+
+	RenderWindowPtr RenderWindowManager::create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
+	{
+		UINT32 id = RenderWindowCoreManager::instance().mNextWindowId.fetch_add(1, std::memory_order_relaxed);
+
+		RenderWindowPtr renderWindow = createImpl(desc, id, parentWindow);
+		renderWindow->_setThisPtr(renderWindow);
+		
+		{
+			BS_LOCK_MUTEX(mWindowMutex);
+
+			mWindows[renderWindow->mWindowId] = renderWindow.get();
+		}
+
+		renderWindow->initialize();
+		
+		return renderWindow;
+	}
+
+	void RenderWindowManager::notifyWindowDestroyed(RenderWindow* window)
+	{
+		{
+			BS_LOCK_MUTEX(mWindowMutex);
+
+			auto iterFind = std::find_if(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), 
+				[&](const MoveOrResizeData& x) { return x.window == window; });
+
+			if(iterFind != mMovedOrResizedWindows.end())
+				mMovedOrResizedWindows.erase(iterFind);
+
+			if (mNewWindowInFocus == window)
+				mNewWindowInFocus = nullptr;
+
+			mWindows.erase(window->mWindowId);
+			mDirtyProperties.erase(window);
+		}
+	}
+
+	void RenderWindowManager::notifyFocusReceived(RenderWindowCore* coreWindow)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		RenderWindow* window = getNonCore(coreWindow);
+		mNewWindowInFocus = window;
+	}
+
+	void RenderWindowManager::notifyFocusLost(RenderWindowCore* coreWindow)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		mNewWindowInFocus = nullptr;
+	}
+
+	void RenderWindowManager::notifyMovedOrResized(RenderWindowCore* coreWindow)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		RenderWindow* window = getNonCore(coreWindow);
+		if (window == nullptr)
+			return;
+
+		auto iterFind = std::find_if(begin(mMovedOrResizedWindows), end(mMovedOrResizedWindows), 
+			[&](const MoveOrResizeData& x) { return x.window == window; });
+
+		const RenderWindowProperties& props = coreWindow->getProperties();
+		MoveOrResizeData* moveResizeData = nullptr;
+
+		if (iterFind != end(mMovedOrResizedWindows))
+		{
+			moveResizeData = &*iterFind;
+		}
+		else
+		{
+			MoveOrResizeData newEntry;
+			newEntry.window = window;
+
+			mMovedOrResizedWindows.push_back(newEntry);
+			moveResizeData = &mMovedOrResizedWindows.back();
+		}
+		
+		moveResizeData->x = props.getLeft();
+		moveResizeData->y = props.getTop();
+		moveResizeData->width = props.getWidth();
+		moveResizeData->height = props.getHeight();
+	}
+
+	void RenderWindowManager::notifySyncDataDirty(RenderWindowCore* coreWindow)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		RenderWindow* window = getNonCore(coreWindow);
+
+		if (window != nullptr)
+			mDirtyProperties.insert(window);
+	}
+
+	void RenderWindowManager::windowMouseLeft(RenderWindowCore* coreWindow)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		RenderWindow* window = getNonCore(coreWindow);
+		auto iterFind = std::find(begin(mMouseLeftWindows), end(mMouseLeftWindows), window);
+
+		if (iterFind == end(mMouseLeftWindows))
+			mMouseLeftWindows.push_back(window);
+	}
+
+	void RenderWindowManager::_update()
+	{
+		RenderWindow* newWinInFocus = nullptr;
+		Vector<MoveOrResizeData> movedOrResizedWindows;
+		Vector<RenderWindow*> mouseLeftWindows;
+
+		{
+			BS_LOCK_MUTEX(mWindowMutex);
+			newWinInFocus = mNewWindowInFocus;
+
+			for (auto& moveResizeData : mMovedOrResizedWindows)
+			{
+				RenderWindow* window = moveResizeData.window;
+				const RenderWindowProperties& props = window->getProperties();
+
+				// Need to eliminate non-dirty ones because it's possible we already triggered the resize event
+				// if the resize call originated from the sim thread, so we don't trigger it twice.
+
+				bool isDirty = moveResizeData.x != props.getLeft() || moveResizeData.y != props.getTop()
+					|| moveResizeData.width != props.getWidth() || moveResizeData.height != props.getHeight();
+
+				if (isDirty)
+					movedOrResizedWindows.push_back(moveResizeData);
+			}
+
+			mMovedOrResizedWindows.clear();
+
+			mouseLeftWindows = mMouseLeftWindows;
+			mMouseLeftWindows.clear();
+
+			for (auto& dirtyPropertyWindow : mDirtyProperties)
+				dirtyPropertyWindow->syncProperties();
+
+			mDirtyProperties.clear();
+		}
+
+		if(mWindowInFocus != newWinInFocus)
+		{
+			if(mWindowInFocus != nullptr)
+				onFocusLost(*mWindowInFocus);
+
+			if(newWinInFocus != nullptr)
+				onFocusGained(*newWinInFocus);
+
+			mWindowInFocus = newWinInFocus;
+		}
+
+		for (auto& moveResizeData : movedOrResizedWindows)
+		{
+			moveResizeData.window->onResized();
+		}
+
+		if (!onMouseLeftWindow.empty())
+		{
+			for (auto& window : mouseLeftWindows)
+				onMouseLeftWindow(*window);
+		}			
+	}
+
+	Vector<RenderWindow*> RenderWindowManager::getRenderWindows() const
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		Vector<RenderWindow*> windows;
+		for (auto& windowPair : mWindows)
+			windows.push_back(windowPair.second);
+
+		return windows;
+	}
+
+	RenderWindow* RenderWindowManager::getNonCore(const RenderWindowCore* window) const
+	{
+		auto iterFind = mWindows.find(window->mWindowId);
+
+		if (iterFind != mWindows.end())
+			return iterFind->second;
+
+		return nullptr;
+	}
+
+	RenderWindowCoreManager::RenderWindowCoreManager()
+	{
+		mNextWindowId = 0;
+	}
+
+	SPtr<RenderWindowCore> RenderWindowCoreManager::create(RENDER_WINDOW_DESC& desc)
+	{
+		UINT32 id = mNextWindowId.fetch_add(1, std::memory_order_relaxed);
+
+		SPtr<RenderWindowCore> renderWindow = createInternal(desc, id);
+		renderWindow->initialize();
+
+		return renderWindow;
+	}
+
+	void RenderWindowCoreManager::_update()
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		for (auto& dirtyPropertyWindow : mDirtyProperties)
+			dirtyPropertyWindow->syncProperties();
+
+		mDirtyProperties.clear();
+	}
+
+	void RenderWindowCoreManager::windowCreated(RenderWindowCore* window)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		mCreatedWindows.push_back(window);
+	}
+
+	void RenderWindowCoreManager::windowDestroyed(RenderWindowCore* window)
+	{
+		{
+			BS_LOCK_MUTEX(mWindowMutex);
+
+			auto iterFind = std::find(begin(mCreatedWindows), end(mCreatedWindows), window);
+
+			if (iterFind == mCreatedWindows.end())
+				BS_EXCEPT(InternalErrorException, "Trying to destroy a window that is not in the created windows list.");
+
+			mCreatedWindows.erase(iterFind);
+			mDirtyProperties.erase(window);
+		}
+	}
+
+	Vector<RenderWindowCore*> RenderWindowCoreManager::getRenderWindows() const
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		return mCreatedWindows;
+	}
+
+	void RenderWindowCoreManager::notifySyncDataDirty(RenderWindowCore* window)
+	{
+		BS_LOCK_MUTEX(mWindowMutex);
+
+		mDirtyProperties.insert(window);
+	}
 }

+ 14 - 143
BansheeCore/Source/Win32/BsWin32Platform.cpp

@@ -9,6 +9,7 @@
 #include "Win32/BsWin32Defs.h"
 #include "Win32/BsWin32DropTarget.h"
 #include "Win32/BsWin32PlatformData.h"
+#include "Win32/BsWin32PlatformUtility.h"
 #include "TimeAPI.h"
 
 namespace BansheeEngine
@@ -156,8 +157,12 @@ namespace BansheeEngine
 
 		mData->mUsingCustomCursor = true;
 
-		HBITMAP hBitmap = Win32Platform::createBitmap(pixelData, false); 
-		HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, nullptr);
+		Vector<Color> pixels = pixelData.getColors();
+		UINT32 width = pixelData.getWidth();
+		UINT32 height = pixelData.getHeight();
+
+		HBITMAP hBitmap = Win32PlatformUtility::createBitmap((Color*)pixels.data(), width, height, false);
+		HBITMAP hMonoBitmap = CreateBitmap(width, height, 1, 1, nullptr);
 
 		ICONINFO iconinfo = {0};
 		iconinfo.fIcon = FALSE;
@@ -184,8 +189,12 @@ namespace BansheeEngine
 		PixelDataPtr resizedData = PixelData::create(32, 32, 1, PF_R8G8B8A8);
 		PixelUtil::scale(pixelData, *resizedData);
 
-		HBITMAP hBitmap = Win32Platform::createBitmap(pixelData, false);
-		HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, nullptr);
+		Vector<Color> pixels = pixelData.getColors();
+		UINT32 width = pixelData.getWidth();
+		UINT32 height = pixelData.getHeight();
+
+		HBITMAP hBitmap = Win32PlatformUtility::createBitmap((Color*)pixels.data(), width, height, false);
+		HBITMAP hMonoBitmap = CreateBitmap(width, height, 1, 1, nullptr);
 
 		ICONINFO iconinfo = { 0 };
 		iconinfo.fIcon = TRUE;
@@ -473,56 +482,7 @@ namespace BansheeEngine
 		return false;
 	}
 
-	HBITMAP Win32Platform::createBitmap(const PixelData& pixelData, bool premultiplyAlpha)
-	{
-		BITMAPINFO bi;
-
-		ZeroMemory(&bi, sizeof(BITMAPINFO));
-		bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-		bi.bmiHeader.biWidth = pixelData.getWidth();
-		bi.bmiHeader.biHeight = pixelData.getHeight();
-		bi.bmiHeader.biPlanes = 1;
-		bi.bmiHeader.biBitCount = 32;
-		bi.bmiHeader.biCompression = BI_RGB;
-
-		HDC hDC = GetDC(nullptr);
-
-		void* data = nullptr;
-		HBITMAP hBitmap = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, (void**)&data, nullptr, 0);
-
-		HDC hBitmapDC = CreateCompatibleDC(hDC);
-		ReleaseDC(nullptr, hDC);
-
-		//Select the bitmaps to DC
-		HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
-
-		//Scan each pixel of the source bitmap and create the masks
-		Color pixel;
-		DWORD *dst = (DWORD*)data;
-		for (UINT32 y = 0; y < pixelData.getHeight(); ++y)
-		{
-			for (UINT32 x = 0; x < pixelData.getWidth(); ++x)
-			{
-				pixel = pixelData.getColorAt(x, pixelData.getHeight() - y - 1);
-
-				if (premultiplyAlpha)
-				{
-					pixel.r *= pixel.a;
-					pixel.g *= pixel.a;
-					pixel.b *= pixel.a;
-				}
-
-				*dst = pixel.getAsBGRA();
-
-				dst++;
-			}
-		}
-
-		SelectObject(hBitmapDC, hOldBitmap);
-		DeleteDC(hBitmapDC);
-
-		return hBitmap;
-	}
+	
 
 	LRESULT CALLBACK Win32Platform::_win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	{
@@ -536,50 +496,6 @@ namespace BansheeEngine
 				const RenderWindowProperties& props = newWindow->getProperties();
 				if (!props.isHidden())
 					ShowWindow(hWnd, SW_SHOWNOACTIVATE);
-
-				if (props.isModal())
-				{
-					if (!mData->mModalWindowStack.empty())
-					{
-						RenderWindowCore* curModalWindow = mData->mModalWindowStack.back();
-
-						UINT64 curHwnd;
-						curModalWindow->getCustomAttribute("WINDOW", &curHwnd);
-						EnableWindow((HWND)curHwnd, FALSE);
-					}
-					else
-					{
-						Vector<RenderWindowCore*> renderWindows = RenderWindowCoreManager::instance().getRenderWindows();
-						for (auto& renderWindow : renderWindows)
-						{
-							if (renderWindow == newWindow)
-								continue;
-
-							UINT64 curHwnd;
-							renderWindow->getCustomAttribute("WINDOW", &curHwnd);
-							EnableWindow((HWND)curHwnd, FALSE);
-						}
-					}
-
-					mData->mModalWindowStack.push_back(newWindow);
-				}
-				else
-				{
-					// A non-modal window was opened while another modal one is open:
-					// immediately deactivate it and make sure the modal windows stay on top
-					if (!mData->mModalWindowStack.empty())
-					{
-						EnableWindow((HWND)hWnd, FALSE);
-
-						for (auto window : mData->mModalWindowStack)
-						{
-							UINT64 curHwnd;
-							window->getCustomAttribute("WINDOW", &curHwnd);
-
-							BringWindowToTop((HWND)curHwnd);
-						}
-					}
-				}
 			}
 			else
 				ShowWindow(hWnd, SW_SHOWNOACTIVATE);
@@ -587,56 +503,12 @@ namespace BansheeEngine
 			return 0;
 		}
 
-		// look up window instance
-		// note: it is possible to get a WM_SIZE before WM_CREATE
 		RenderWindowCore* win = (RenderWindowCore*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
 		if (!win)
 			return DefWindowProc(hWnd, uMsg, wParam, lParam);
 
 		switch( uMsg )
 		{
-		case WM_DESTROY:
-			{
-				bool reenableWindows = false;
-				if (!mData->mModalWindowStack.empty())
-				{
-					// Start from back because the most common case is closing the top-most modal window
-					for (auto iter = mData->mModalWindowStack.rbegin(); iter != mData->mModalWindowStack.rend(); ++iter)
-					{
-						if (*iter == win)
-						{
-							auto iterFwd = std::next(iter).base(); // erase doesn't accept reverse iter, so convert
-
-							mData->mModalWindowStack.erase(iterFwd);
-							break;
-						}
-					}
-
-					if (!mData->mModalWindowStack.empty()) // Enable next modal window
-					{
-						RenderWindowCore* curModalWindow = mData->mModalWindowStack.back();
-
-						UINT64 curHwnd;
-						curModalWindow->getCustomAttribute("WINDOW", &curHwnd);
-						EnableWindow((HWND)curHwnd, TRUE);
-					}
-					else
-						reenableWindows = true; // No more modal windows, re-enable any remaining window
-				}
-
-				if(reenableWindows)
-				{
-					Vector<RenderWindowCore*> renderWindows = RenderWindowCoreManager::instance().getRenderWindows();
-					for(auto& renderWindow : renderWindows)
-					{
-						HWND curHwnd;
-						renderWindow->getCustomAttribute("WINDOW", &curHwnd);
-						EnableWindow(curHwnd, TRUE);
-					}
-				}
-
-				return 0;
-			}
 		case WM_SETFOCUS:
 			{
 				if (!win->getProperties().hasFocus())
@@ -652,7 +524,6 @@ namespace BansheeEngine
 				return 0;
 			}
 		case WM_SYSCHAR:
-			// return zero to bypass defProc and signal we processed the message, unless it's an ALT-space
 			if (wParam != VK_SPACE)
 				return 0;
 			break;

+ 2 - 0
BansheeD3D11RenderAPI/Source/BsD3D11RenderWindow.cpp

@@ -77,6 +77,8 @@ namespace BansheeEngine
 		windowDesc.title = mDesc.title;
 		windowDesc.toolWindow = mDesc.toolWindow;
 		windowDesc.creationParams = this;
+		windowDesc.modal = mDesc.modal;
+		windowDesc.wndProc = &Win32Platform::_win32WndProc;
 
 #ifdef BS_STATIC_LIB
 		windowDesc.module = GetModuleHandle(NULL);

+ 2 - 0
BansheeD3D9RenderAPI/Source/BsD3D9RenderWindow.cpp

@@ -69,6 +69,8 @@ namespace BansheeEngine
 		windowDesc.toolWindow = mDesc.toolWindow;
 		windowDesc.creationParams = this;
 		windowDesc.module = mInstance;
+		windowDesc.modal = mDesc.modal;
+		windowDesc.wndProc = &Win32Platform::_win32WndProc;
 
 		NameValuePairList::const_iterator opt;
 		opt = mDesc.platformSpecific.find("parentWindowHandle");

+ 1 - 1
BansheeEngine/Source/BsLight.cpp

@@ -78,7 +78,7 @@ namespace BansheeEngine
 	{
 		// When lower than this attenuation light influence is assumed to be zero
 		const float minAttenuation = 0.05f;
-		mRange = sqrt(mIntensity / minAttenuation - 1.0f);
+		mRange = sqrt(std::max(0.0f, mIntensity / minAttenuation - 1.0f));
 
 		updateBounds();
 	}

+ 6 - 1
BansheeEngine/Source/BsSplashScreen.cpp

@@ -5,6 +5,7 @@
 #include "BsTimer.h"
 
 #if BS_PLATFORM == BS_PLATFORM_WIN32
+#include "Win32/BsWin32Platform.h"
 #include "Win32/BsWin32Window.h"
 
 namespace BansheeEngine
@@ -33,12 +34,16 @@ namespace BansheeEngine
 		windowDesc.title = "Banshee Splash";
 		windowDesc.toolWindow = true;
 		windowDesc.alphaBlending = true;
+		windowDesc.wndProc = Win32Platform::_win32WndProc;
 
 		PixelDataPtr splashPixelData = BuiltinResources::getSplashScreen();
 		if (splashPixelData == nullptr)
 			return;
 
-		windowDesc.background = splashPixelData;
+		Vector<Color> pixels = splashPixelData->getColors();
+		windowDesc.backgroundPixels = (Color*)pixels.data();
+		windowDesc.backgroundWidth = splashPixelData->getWidth();
+		windowDesc.backgroundHeight = splashPixelData->getHeight();
 
 		m->window = bs_new<Win32Window>(windowDesc);
 		m->timer.reset();

+ 2 - 0
BansheeGLRenderAPI/Source/win32/BsWin32RenderWindow.cpp

@@ -79,6 +79,8 @@ namespace BansheeEngine
 		windowDesc.title = mDesc.title;
 		windowDesc.toolWindow = mDesc.toolWindow;
 		windowDesc.creationParams = this;
+		windowDesc.modal = mDesc.modal;
+		windowDesc.wndProc = &Win32Platform::_win32WndProc;
 
 #ifdef BS_STATIC_LIB
 		windowDesc.module = GetModuleHandle(NULL);

+ 3 - 0
BansheeUtility/BansheeUtility.vcxproj

@@ -311,6 +311,7 @@
     <ClCompile Include="Source\Win32\BsWin32FileSystem.cpp" />
     <ClCompile Include="Source\Win32\BsWin32PlatformUtility.cpp" />
     <ClCompile Include="Source\Win32\BsWin32Timer.cpp" />
+    <ClCompile Include="Source\Win32\BsWin32Window.cpp" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsBinaryCloner.h" />
     <ClInclude Include="Include\BsBitmapWriter.h" />
@@ -401,6 +402,8 @@
     <ClInclude Include="Include\BsVectorNI.h" />
     <ClInclude Include="Include\BsGlobalFrameAlloc.h" />
     <ClInclude Include="Include\ThirdParty\md5.h" />
+    <ClInclude Include="Include\Win32\BsWin32PlatformUtility.h" />
+    <ClInclude Include="Include\Win32\BsWin32Window.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsColor.cpp" />

+ 12 - 0
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -96,6 +96,9 @@
     <Filter Include="Source Files\Image">
       <UniqueIdentifier>{dea9161b-d3f5-401f-9005-aceafe004b3d}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\Win32">
+      <UniqueIdentifier>{0c62f506-fd7d-401d-9fca-2382da459269}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsThreadDefines.h">
@@ -353,6 +356,12 @@
     <ClInclude Include="Include\BsRTTIPrerequisites.h">
       <Filter>Header Files\Prerequisites</Filter>
     </ClInclude>
+    <ClInclude Include="Include\Win32\BsWin32PlatformUtility.h">
+      <Filter>Header Files\Win32</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\Win32\BsWin32Window.h">
+      <Filter>Header Files\Win32</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsAsyncOp.cpp">
@@ -541,5 +550,8 @@
     <ClCompile Include="Source\BsUtil.cpp">
       <Filter>Source Files\General</Filter>
     </ClCompile>
+    <ClCompile Include="Source\Win32\BsWin32Window.cpp">
+      <Filter>Source Files\Win32</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 8 - 0
BansheeUtility/Include/BsFwdDeclUtil.h

@@ -21,6 +21,14 @@ namespace BansheeEngine
 		ZYX
 	};
 
+	/**	Enum that defines possible window border styles. */
+	enum class WindowBorder
+	{
+		Normal,
+		None,
+		Fixed
+	};
+
 	/** @} */
 
 	class Angle;

+ 4 - 0
BansheeUtility/Include/BsPrerequisitesUtil.h

@@ -66,6 +66,10 @@
  *  Types containing RTTI for specific classes.
  */
 
+/** @defgroup Platform-Utility Platform
+ *  Platform specific functionality.
+ */
+
 /** @} */
 
 /** @defgroup Implementation Implementation

+ 27 - 0
BansheeUtility/Include/Win32/BsWin32PlatformUtility.h

@@ -0,0 +1,27 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+#include "BsPrerequisitesUtil.h"
+#include <windows.h>
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Platform-Utility
+	 *  @{
+	 */
+
+	/** Provides access to various Windows specific utility functions. */
+	class BS_UTILITY_EXPORT Win32PlatformUtility
+	{
+	public:
+		/**
+		 * Creates a new bitmap usable by various Win32 methods from the provided pixel data. Caller must ensure to call 
+		 * DeleteObject() on the bitmap handle when finished.
+		 */
+		static HBITMAP createBitmap(const Color* pixels, UINT32 width, UINT32 height, bool premultiplyAlpha);
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 38 - 9
BansheeCore/Include/Win32/BsWin32Window.h → BansheeUtility/Include/Win32/BsWin32Window.h

@@ -2,24 +2,25 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #pragma once
 
-#include "BsCorePrerequisites.h"
+#include "BsPrerequisitesUtil.h"
 #include "BsVector2I.h"
 #include "windows.h"
 
 namespace BansheeEngine
 {
 	/** @cond INTERNAL */
-	/** @addtogroup Platform-Core
+	/** @addtogroup Platform-Utility
 	 *  @{
 	 */
 
 	/**	Descriptor used for creating a platform specific native window. */
-	struct BS_CORE_EXPORT WINDOW_DESC
+	struct BS_UTILITY_EXPORT WINDOW_DESC
 	{
 		WINDOW_DESC()
 			: module(nullptr), monitor(nullptr), parent(nullptr), external(nullptr), width(0), height(0), fullscreen(false)
 			, hidden(false), left(-1), top(-1), title(""), border(WindowBorder::Normal), outerDimensions(false)
-			, enableDoubleClick(true), toolWindow(false), creationParams(nullptr), alphaBlending(false)
+			, enableDoubleClick(true), toolWindow(false), creationParams(nullptr), alphaBlending(false), modal(false)
+			, wndProc(nullptr), backgroundPixels(nullptr), backgroundWidth(0), backgroundHeight(0)
 		{ }
 
 		HINSTANCE module; /**< Instance to the local module. */
@@ -37,13 +38,23 @@ namespace BansheeEngine
 		WindowBorder border; /**< Type of border to create the window with. */
 		bool outerDimensions; /**< Do our dimensions include space for things like title-bar and border. */
 		bool enableDoubleClick; /**< Does window accept double-clicks. */
-		bool toolWindow; /**< Tool windows have a different style than normal windows and can be created with no border or title bar. */
-		PixelDataPtr background; /**< Optional background image to apply to the window. */
-		bool alphaBlending; /**< If true the window will support transparency based on the alpha channel of the background image. */
+		/** Tool windows have a different style than normal windows and can be created with no border or title bar. */
+		bool toolWindow; 
+		/**
+		 * Optional background image to apply to the window. This must be a buffer of size 
+		 * backgroundWidth * backgroundHeight. 
+		 */
+		Color* backgroundPixels;
+		UINT32 backgroundWidth; /** Width of the background image. Only relevant if backgroundPixels is not null. */
+		UINT32 backgroundHeight; /** Width of the background image. Only relevant if backgroundPixels is not null. */
+		/** If true the window will support transparency based on the alpha channel of the background image. */
+		bool alphaBlending; 
+		bool modal; /**< When a modal window is open all other windows will be locked until modal window is closed. */
+		WNDPROC wndProc; /**< Pointer to a function that handles windows message processing. */
 	};
 
 	/**	Represents a Windows native window. */
-	class BS_CORE_EXPORT Win32Window
+	class BS_UTILITY_EXPORT Win32Window
 	{
 	public:
 		Win32Window(const WINDOW_DESC& desc);
@@ -99,10 +110,28 @@ namespace BansheeEngine
 
 		/** Called when window is moved or resized externally. */
 		void _windowMovedOrResized();
-
 	private:
+		friend class Win32WindowManager;
+
 		struct Pimpl;
 		Pimpl* m;
+
+		static Vector<Win32Window*> sAllWindows;
+		static Vector<Win32Window*> sModalWindowStack;
+		static Mutex sWindowsMutex;
+	};
+
+	/** Tracks all created Windows windows. */
+	class BS_UTILITY_EXPORT Win32WindowManager
+	{
+		/** Should be called whenever a new window is created. */
+		static void _registerWindow(Win32Window* window);
+
+		/** Should be called just before a window is destroyed. */
+		static void _unregisterWindow(Win32Window* window);
+
+		///** Enables all windows that are currently disabled (don't accept mouse and keyboard input) */
+		//static void _enableAllWindows();
 	};
 
 	/** @} */

+ 2 - 0
BansheeUtility/Source/Win32/BsWin32BrowseDialogs.cpp

@@ -1,6 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsPrerequisitesUtil.h"
+#include "Win32/BsWin32Window.h"
 #include <atlbase.h>
 #include <ShObjIdl.h>
 
@@ -116,6 +117,7 @@ namespace BansheeEngine
 
 		// Show the dialog
 		bool finalResult = false;
+
 		if (SUCCEEDED(fileDialog->Show(nullptr)))
 		{
 			if (isMultiselect)

+ 54 - 0
BansheeUtility/Source/Win32/BsWin32PlatformUtility.cpp

@@ -1,6 +1,8 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsPrerequisitesUtil.h"
+#include "Win32/BsWin32PlatformUtility.h"
+#include "BsColor.h"
 #include <windows.h>
 #include <iphlpapi.h>
 
@@ -150,4 +152,56 @@ namespace BansheeEngine
 	{
 		ShellExecute(nullptr, "open", path.toString().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
 	}
+
+	HBITMAP Win32PlatformUtility::createBitmap(const Color* pixels, UINT32 width, UINT32 height, bool premultiplyAlpha)
+	{
+		BITMAPINFO bi;
+
+		ZeroMemory(&bi, sizeof(BITMAPINFO));
+		bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+		bi.bmiHeader.biWidth = width;
+		bi.bmiHeader.biHeight = height;
+		bi.bmiHeader.biPlanes = 1;
+		bi.bmiHeader.biBitCount = 32;
+		bi.bmiHeader.biCompression = BI_RGB;
+
+		HDC hDC = GetDC(nullptr);
+
+		void* data = nullptr;
+		HBITMAP hBitmap = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, (void**)&data, nullptr, 0);
+
+		HDC hBitmapDC = CreateCompatibleDC(hDC);
+		ReleaseDC(nullptr, hDC);
+
+		//Select the bitmaps to DC
+		HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
+
+		//Scan each pixel of the source bitmap and create the masks
+		Color pixel;
+		DWORD *dst = (DWORD*)data;
+		for (UINT32 y = 0; y < height; ++y)
+		{
+			for (UINT32 x = 0; x < width; ++x)
+			{
+				UINT32 revY = height - y - 1;
+				pixel = pixels[revY * width + x];
+
+				if (premultiplyAlpha)
+				{
+					pixel.r *= pixel.a;
+					pixel.g *= pixel.a;
+					pixel.b *= pixel.a;
+				}
+
+				*dst = pixel.getAsBGRA();
+
+				dst++;
+			}
+		}
+
+		SelectObject(hBitmapDC, hOldBitmap);
+		DeleteDC(hBitmapDC);
+
+		return hBitmap;
+	}
 }

+ 118 - 7
BansheeCore/Source/Win32/BsWin32Window.cpp → BansheeUtility/Source/Win32/BsWin32Window.cpp

@@ -1,10 +1,14 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Win32/BsWin32Window.h"
-#include "Win32/BsWin32Platform.h"
+#include "Win32/BsWin32PlatformUtility.h"
 
 namespace BansheeEngine
 {
+	Vector<Win32Window*> Win32Window::sAllWindows;
+	Vector<Win32Window*> Win32Window::sModalWindowStack;
+	Mutex Win32Window::sWindowsMutex;
+
 	struct Win32Window::Pimpl
 	{
 		HWND hWnd = nullptr;
@@ -13,6 +17,7 @@ namespace BansheeEngine
 		UINT32 width = 0;
 		UINT32 height = 0;
 		bool isExternal = false;
+		bool isModal = false;
 		DWORD style = 0;
 		DWORD styleEx = 0;
 	};
@@ -20,6 +25,7 @@ namespace BansheeEngine
 	Win32Window::Win32Window(const WINDOW_DESC& desc)
 	{
 		m = bs_new<Pimpl>();
+		m->isModal = desc.modal;
 
 		HMONITOR hMonitor = desc.monitor;
 		if (!desc.external)
@@ -128,7 +134,7 @@ namespace BansheeEngine
 						top = (screenh - height) / 2;
 				}
 
-				if (desc.background != nullptr)
+				if (desc.backgroundPixels != nullptr)
 					m->styleEx |= WS_EX_LAYERED;
 			}
 			else
@@ -143,7 +149,7 @@ namespace BansheeEngine
 				classStyle |= CS_DBLCLKS;
 
 			// Register the window class
-			WNDCLASS wc = { classStyle, Win32Platform::_win32WndProc, 0, 0, desc.module,
+			WNDCLASS wc = { classStyle, desc.wndProc, 0, 0, desc.module,
 				LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW),
 				(HBRUSH)GetStockObject(BLACK_BRUSH), 0, "Win32Wnd" };
 
@@ -170,9 +176,10 @@ namespace BansheeEngine
 		m->height = rect.bottom;
 
 		// Set background, if any
-		if (desc.background != nullptr)
+		if (desc.backgroundPixels != nullptr)
 		{
-			HBITMAP backgroundBitmap = Win32Platform::createBitmap(*desc.background, true);
+			HBITMAP backgroundBitmap = Win32PlatformUtility::createBitmap(
+				desc.backgroundPixels, desc.backgroundWidth, desc.backgroundHeight, true);
 
 			HDC hdcScreen = GetDC(nullptr);
 			HDC hdcMem = CreateCompatibleDC(hdcScreen);
@@ -200,12 +207,116 @@ namespace BansheeEngine
 			DeleteDC(hdcMem);
 			ReleaseDC(nullptr, hdcScreen);
 		}
+
+		// Handle modal windows
+		bs_frame_mark();
+
+		{
+			FrameVector<HWND> windowsToDisable;
+			FrameVector<HWND> windowsToBringToFront;
+			{
+				BS_LOCK_MUTEX(sWindowsMutex);
+
+				if (m->isModal)
+				{
+					if (!sModalWindowStack.empty())
+					{
+						Win32Window* curModalWindow = sModalWindowStack.back();
+						windowsToDisable.push_back(curModalWindow->m->hWnd);
+					}
+					else
+					{
+						for (auto& window : sAllWindows)
+							windowsToDisable.push_back(window->m->hWnd);
+					}
+
+					sModalWindowStack.push_back(this);
+				}
+				else
+				{
+					// A non-modal window was opened while another modal one is open,
+					// immediately deactivate it and make sure the modal windows stay on top.
+					if (!sModalWindowStack.empty())
+					{
+						windowsToDisable.push_back(m->hWnd);
+
+						for (auto window : sModalWindowStack)
+							windowsToBringToFront.push_back(window->m->hWnd);
+					}
+				}
+
+				sAllWindows.push_back(this);
+			}
+
+			for(auto& entry : windowsToDisable)
+				EnableWindow(entry, FALSE);
+
+			for (auto& entry : windowsToBringToFront)
+				BringWindowToTop(entry);
+		}
+
+		bs_frame_clear();
 	}
 
 	Win32Window::~Win32Window()
 	{
 		if (m->hWnd && !m->isExternal)
+		{
+			// Handle modal windows
+			bs_frame_mark();
+			
+			{
+				FrameVector<HWND> windowsToEnable;
+				{
+					BS_LOCK_MUTEX(sWindowsMutex);
+
+					// Hidden dependency: All windows must be re-enabled before a window is destroyed, otherwise the incorrect
+					// window in the z order will be activated.
+					bool reenableWindows = false;
+					if (!sModalWindowStack.empty())
+					{
+						// Start from back because the most common case is closing the top-most modal window
+						for (auto iter = sModalWindowStack.rbegin(); iter != sModalWindowStack.rend(); ++iter)
+						{
+							if (*iter == this)
+							{
+								auto iterFwd = std::next(iter).base(); // erase doesn't accept reverse iter, so convert
+
+								sModalWindowStack.erase(iterFwd);
+								break;
+							}
+						}
+
+						if (!sModalWindowStack.empty()) // Enable next modal window
+						{
+							Win32Window* curModalWindow = sModalWindowStack.back();
+							windowsToEnable.push_back(curModalWindow->m->hWnd);
+						}
+						else
+							reenableWindows = true; // No more modal windows, re-enable any remaining window
+					}
+
+					if (reenableWindows)
+					{
+						for (auto& window : sAllWindows)
+							windowsToEnable.push_back(window->m->hWnd);
+					}
+				}
+
+				for(auto& entry : windowsToEnable)
+					EnableWindow(entry, TRUE);
+			}
+			bs_frame_clear();
+
 			DestroyWindow(m->hWnd);
+		}
+
+		{
+			BS_LOCK_MUTEX(sWindowsMutex);
+
+			auto iterFind = std::find(sAllWindows.begin(), sAllWindows.end(), this);
+			sAllWindows.erase(iterFind);
+		}
 
 		bs_delete(m);
 	}
@@ -217,7 +328,7 @@ namespace BansheeEngine
 			m->top = top;
 			m->left = left;
 
-			SetWindowPos(m->hWnd, nullptr, left, top, m->width, m->height, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+			SetWindowPos(m->hWnd, HWND_TOP, left, top, m->width, m->height, SWP_NOSIZE);
 		}
 	}
 
@@ -233,7 +344,7 @@ namespace BansheeEngine
 			m->width = width;
 			m->height = height;
 
-			SetWindowPos(m->hWnd, nullptr, m->left, m->top, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+			SetWindowPos(m->hWnd, HWND_TOP, m->left, m->top, width, height, SWP_NOMOVE);
 		}
 	}