Просмотр исходного кода

Refactoring platform specific code to be easier to find and to implement for other platforms

Marko Pintera 11 лет назад
Родитель
Сommit
6fe93f22f0

+ 3 - 4
BansheeCore/BansheeCore.vcxproj

@@ -419,11 +419,11 @@
     <ClInclude Include="Include\BsVertexDeclarationRTTI.h" />
     <ClInclude Include="Include\BsTechnique.h" />
     <ClInclude Include="Include\BsViewportRTTI.h" />
-    <ClInclude Include="Include\Win32\BsPlatformImpl.h" />
     <ClInclude Include="Include\Win32\BsWin32Defs.h" />
-    <ClInclude Include="Include\Win32\BsPlatformWndProc.h" />
+    <ClInclude Include="Include\Win32\BsWin32Platform.h" />
     <ClInclude Include="Include\Win32\BsWin32DropTarget.h" />
     <ClInclude Include="Include\Win32\BsWin32FolderMonitor.h" />
+    <ClInclude Include="Include\Win32\BSWin32PlatformData.h" />
     <ClInclude Include="Source\BsMeshRTTI.h" />
   </ItemGroup>
   <ItemGroup>
@@ -526,8 +526,7 @@
     <ClCompile Include="Source\BsViewport.cpp" />
     <ClCompile Include="Source\BsSceneObject.cpp" />
     <ClCompile Include="Source\BsComponent.cpp" />
-    <ClCompile Include="Source\Win32\BsPlatformImpl.cpp" />
-    <ClCompile Include="Source\Win32\BsPlatformWndProc.cpp" />
+    <ClCompile Include="Source\Win32\BsWin32Platform.cpp" />
     <ClCompile Include="Source\Win32\BsWin32FolderMonitor.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 15 - 21
BansheeCore/BansheeCore.vcxproj.filters

@@ -57,9 +57,6 @@
     <Filter Include="Header Files\Win32">
       <UniqueIdentifier>{1d3fe8eb-ec10-4356-90f0-b27f89f01a13}</UniqueIdentifier>
     </Filter>
-    <Filter Include="Source Files\Win32">
-      <UniqueIdentifier>{5a1e28c5-e784-44e6-974f-f1d0d66474ed}</UniqueIdentifier>
-    </Filter>
     <Filter Include="Header Files\Text">
       <UniqueIdentifier>{1daa1a6e-95c0-4e63-b339-4a884773fa64}</UniqueIdentifier>
     </Filter>
@@ -113,15 +110,6 @@
     <ClInclude Include="Include\BsDeferredCallManager.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="Include\Win32\BsWin32Defs.h">
-      <Filter>Header Files\Win32</Filter>
-    </ClInclude>
-    <ClInclude Include="Include\Win32\BsPlatformImpl.h">
-      <Filter>Header Files\Win32</Filter>
-    </ClInclude>
-    <ClInclude Include="Include\Win32\BsPlatformWndProc.h">
-      <Filter>Header Files\Win32</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsTextData.h">
       <Filter>Header Files\Text</Filter>
     </ClInclude>
@@ -530,6 +518,15 @@
     <ClInclude Include="Include\BsSavedResourceDataRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\Win32\BsWin32Defs.h">
+      <Filter>Header Files\Platform</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\Win32\BSWin32PlatformData.h">
+      <Filter>Header Files\Platform</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\Win32\BsWin32Platform.h">
+      <Filter>Header Files\Platform</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -541,9 +538,6 @@
     <ClCompile Include="Source\BsUUID.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsPlatform.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsPixelVolume.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -556,12 +550,6 @@
     <ClCompile Include="Source\BsDeferredCallManager.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Source\Win32\BsPlatformWndProc.cpp">
-      <Filter>Source Files\Win32</Filter>
-    </ClCompile>
-    <ClCompile Include="Source\Win32\BsPlatformImpl.cpp">
-      <Filter>Source Files\Win32</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsFont.cpp">
       <Filter>Source Files\Text</Filter>
     </ClCompile>
@@ -838,5 +826,11 @@
     <ClCompile Include="Source\BsSavedResourceData.cpp">
       <Filter>Source Files\Resources</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPlatform.cpp">
+      <Filter>Source Files\Platform</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\Win32\BsWin32Platform.cpp">
+      <Filter>Source Files\Platform</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 362 - 67
BansheeCore/Include/BsPlatform.h

@@ -1,13 +1,17 @@
 #pragma once
 
 #include "BsCorePrerequisites.h"
+#include "BsInputFwd.h"
+#include "BsVector2I.h"
+#include "BsRect2I.h"
+#include "BsEvent.h"
 
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Contains values representing default
-	 *			mouse cursor types.
-	 */
+	* @brief	Contains values representing default
+	*			mouse cursor types.
+	*/
 	enum class PlatformCursorType
 	{
 		Arrow,
@@ -23,11 +27,11 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Contains values reprenting window non client areas.
-	 *
-	 * @note	These are used for things like resize/move and tell the OS
-	 *			where each of those areas are on our window.
-	 */
+	* @brief	Contains values reprenting window non client areas.
+	*
+	* @note	These are used for things like resize/move and tell the OS
+	*			where each of those areas are on our window.
+	*/
 	enum class NonClientAreaBorderType
 	{
 		TopLeft,
@@ -37,21 +41,21 @@ namespace BansheeEngine
 		Right,
 		BottomLeft,
 		Bottom,
-		BottomRight	
+		BottomRight
 	};
 
 	/**
-	 * @brief	Types of mouse buttons provided by the OS.
-	 */
+	* @brief	Types of mouse buttons provided by the OS.
+	*/
 	enum class OSMouseButton
 	{
 		Left, Middle, Right, Count
 	};
 
 	/**
-	 * @brief	Describes pointer (mouse, touch) states as reported
-	 *			by the OS.
-	 */
+	* @brief	Describes pointer (mouse, touch) states as reported
+	*			by the OS.
+	*/
 	struct BS_CORE_EXPORT OSPointerButtonStates
 	{
 		OSPointerButtonStates()
@@ -69,9 +73,9 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Type of drop event type. This is used
-	 *			when dragging items over drop targets.
-	 */
+	* @brief	Type of drop event type. This is used
+	*			when dragging items over drop targets.
+	*/
 	enum class OSDropType
 	{
 		FileList,
@@ -79,80 +83,80 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Drop targets allow you to register a certain portion of a window as a drop target that
-	 *			accepts certain drop types. Accepted drop types are provided by the OS and include things
-	 *			like file and item dragging.
-	 *
-	 *			You will receive events with the specified drop area as long as it is active.
-	 */
+	* @brief	Drop targets allow you to register a certain portion of a window as a drop target that
+	*			accepts certain drop types. Accepted drop types are provided by the OS and include things
+	*			like file and item dragging.
+	*
+	*			You will receive events with the specified drop area as long as it is active.
+	*/
 	class BS_CORE_EXPORT OSDropTarget
 	{
 	public:
 		/**
-		 * @brief	Triggered when a pointer is being dragged over the drop area.
-		 *			Provides window coordinates of the pointer position.
-		 */
+		* @brief	Triggered when a pointer is being dragged over the drop area.
+		*			Provides window coordinates of the pointer position.
+		*/
 		Event<void(INT32 x, INT32 y)> onDragOver;
 
 		/**
-		 * @brief	Triggered when the user completes a drop while pointer is over
-		 *			the drop area.
-		 *			Provides window coordinates of the pointer position.
-		 */
+		* @brief	Triggered when the user completes a drop while pointer is over
+		*			the drop area.
+		*			Provides window coordinates of the pointer position.
+		*/
 		Event<void(INT32 x, INT32 y)> onDrop;
 
 		/**
-		 * @brief	Triggered when a pointer enters the drop area.
-		 *			Provides window coordinates of the pointer position.
-		 */
+		* @brief	Triggered when a pointer enters the drop area.
+		*			Provides window coordinates of the pointer position.
+		*/
 		Event<void(INT32 x, INT32 y)> onEnter;
 
 		/**
-		 * @brief	Triggered when a pointer leaves the drop area.
-		 */
+		* @brief	Triggered when a pointer leaves the drop area.
+		*/
 		Event<void()> onLeave;
 
 		/**
-		 * @brief	Sets the drop target area, in local window coordinates.
-		 */
+		* @brief	Sets the drop target area, in local window coordinates.
+		*/
 		void setArea(INT32 x, INT32 y, UINT32 width, UINT32 height);
 
 		/**
-		 * @brief	Gets the type of drop that this drop target is looking for. Only
-		 *			valid after a drop has been triggered.
-		 */
+		* @brief	Gets the type of drop that this drop target is looking for. Only
+		*			valid after a drop has been triggered.
+		*/
 		OSDropType getDropType() const { return mDropType; }
 
 		/**
-		 * @brief	Returns a list of files received by the drop target. Only valid
-		 *			after a drop of FileList type has been triggered.
-		 */
+		* @brief	Returns a list of files received by the drop target. Only valid
+		*			after a drop of FileList type has been triggered.
+		*/
 		const Vector<WString>& getFileList() const { return *mFileList; }
 
 		/**
-		 * @brief	Internal method. Clears all internal values.
-		 */
+		* @brief	Internal method. Clears all internal values.
+		*/
 		void _clear();
 
 		/**
-		 * @brief	Internal method. Sets the file list and marks the drop event as FileList.
-		 */
+		* @brief	Internal method. Sets the file list and marks the drop event as FileList.
+		*/
 		void _setFileList(const Vector<WString>& fileList);
 
 		/**
-		 * @brief	Marks the drop area as inactive or active.
-		 */
+		* @brief	Marks the drop area as inactive or active.
+		*/
 		void _setActive(bool active) { mActive = active; }
 
 		/**
-		 * @brief	Checks is the specified position within the current drop area.
-		 *			Position should be in window local coordinates.
-		 */
+		* @brief	Checks is the specified position within the current drop area.
+		*			Position should be in window local coordinates.
+		*/
 		bool _isInside(const Vector2I& pos) const;
 
 		/**
-		 * @brief	Returns true if the drop target is active.
-		 */
+		* @brief	Returns true if the drop target is active.
+		*/
 		bool _isActive() const { return mActive; }
 	private:
 		friend class Platform;
@@ -161,8 +165,8 @@ namespace BansheeEngine
 		~OSDropTarget();
 
 		/**
-		 * @brief	Returns a render window this drop target is attached to.
-		 */
+		* @brief	Returns a render window this drop target is attached to.
+		*/
 		const RenderWindow* getOwnerWindow() const { return mOwnerWindow; }
 	private:
 		INT32 mX, mY;
@@ -172,18 +176,309 @@ namespace BansheeEngine
 
 		OSDropType mDropType;
 
-		union 
+		union
 		{
 			Vector<WString>* mFileList;
 		};
 	};
-}
-
-// Bring in the specific platform's header file
-#if BS_PLATFORM == BS_PLATFORM_WIN32
-# include "Win32/BsPlatformImpl.h"
-#elif (BS_PLATFORM == BS_PLATFORM_LINUX)
-# include "GLX/BsPlatformImpl.h"
-#elif BS_PLATFORM == BS_PLATFORM_APPLE
-# include "OSX/BsPlatformImpl.h"
-#endif
+
+	/**
+	* @brief	Represents a specific non client area used for window resizing.
+	*/
+	struct BS_CORE_EXPORT NonClientResizeArea
+	{
+		NonClientAreaBorderType type;
+		Rect2I area;
+	};
+
+	/**
+	* @brief	Contains a list of window move and resize non client areas.
+	*/
+	struct BS_CORE_EXPORT WindowNonClientAreaData
+	{
+		Vector<NonClientResizeArea> resizeAreas;
+		Vector<Rect2I> moveAreas;
+	};
+
+	/**
+	* @brief	Provides access to various operating system functions, including
+	* 			the main message pump.
+	*/
+	class BS_CORE_EXPORT Platform
+	{
+	public:
+		struct Pimpl;
+
+		Platform() { }
+		virtual ~Platform();
+
+		/**
+		* @brief	Retrieves the cursor position in screen coordinates.
+		*
+		* @note	Thread safe.
+		*/
+		static Vector2I getCursorPosition();
+
+		/**
+		* @brief	Moves the cursor to the specified screen position.
+		*
+		* @note	Thread safe.
+		*/
+		static void setCursorPosition(const Vector2I& screenPos);
+
+		/**
+		* @brief	Capture mouse to this window so that we get mouse input even if the mouse leaves the window area.
+		*
+		* @note	Thread safe.
+		*/
+		static void captureMouse(const RenderWindow& window);
+		/**
+		* @brief	Releases the mouse capture set by "captureMouse"
+		*
+		* @note	Thread safe.
+		*/
+		static void releaseMouseCapture();
+
+		/**
+		* @brief	Checks if provided over screen position is over the specified window.
+		*/
+		static bool isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos);
+
+		/**
+		* @brief	Limit cursor movement to the specified window.
+		*
+		* @note	Thread safe.
+		*/
+		static void clipCursorToWindow(const RenderWindow& window);
+		/**
+		* @brief	Clip cursor to specific area on the screen.
+		*
+		* @note	Thread safe.
+		*/
+		static void clipCursorToRect(const Rect2I& screenRect);
+		/**
+		* @brief	Disables cursor clipping.
+		*
+		* @note	Thread safe.
+		*/
+		static void clipCursorDisable();
+
+		/**
+		* @brief	Hides the cursor.
+		*
+		* @note	Thread safe.
+		*/
+		static void hideCursor();
+		/**
+		* @brief	Shows the cursor.
+		*
+		* @note	Thread safe.
+		*/
+		static void showCursor();
+
+		/**
+		* @brief	Query if the cursor is hidden.
+		*
+		* @note	Thread safe.
+		*/
+		static bool isCursorHidden();
+
+		/**
+		* @brief	Sets a cursor using a custom image.
+		*
+		* @param 	pixelData	Cursor image data.
+		* @param	hotSpot		Offset on the cursor image to where the actual input happens (e.g. tip of the Arrow cursor).
+		*
+		* @note	Thread safe.
+		*/
+		static void setCursor(PixelData& pixelData, const Vector2I& hotSpot);
+
+		/**
+		* @brief	Sets custom caption non client areas for the specified window. Using custom client
+		* 			areas will override window move/drag operation and trigger when user interacts
+		* 			with the custom area.
+		*
+		* @note	Thread safe.
+		* 			All provided areas are relative to the specified window.
+		* 			Mostly useful for frameless windows that don't have typical caption bar.
+		*/
+		static void setCaptionNonClientAreas(const RenderWindowCore& window, const Vector<Rect2I>& nonClientAreas);
+
+		/**
+		* @brief	Sets custom non client areas for the specified window. Using custom client
+		* 			areas will override window resize operation and trigger when user interacts
+		* 			with the custom area.
+		*
+		* @note	Thread safe.
+		* 			All provided areas are relative to the specified window.
+		* 			Mostly useful for frameless windows that don't have typical border.
+		*/
+		static void setResizeNonClientAreas(const RenderWindowCore& window, const Vector<NonClientResizeArea>& nonClientAreas);
+
+		/**
+		* @brief	Resets the non client areas for the specified windows and allows
+		* 			the platform to use the default values.
+		*
+		* @note	Thread safe.
+		*/
+		static void resetNonClientAreas(const RenderWindowCore& window);
+
+		/**
+		* @brief	Adds a string to the clipboard.
+		*
+		* @note	Thread safe.
+		*/
+		static void copyToClipboard(const WString& string);
+
+		/**
+		* @brief	Reads a string from the clipboard and returns it. If there is no
+		* 			string in the clipboard it returns an empty string.
+		*
+		* @note	Both wide and normal strings will be read, but normal strings will be converted to
+		* 			a wide string before returning.
+		*
+		*			Thread safe.
+		*/
+		static WString copyFromClipboard();
+
+		/**
+		* @brief	Populates the provided buffer with a MAC address of the first available
+		*			adapter, if one exists. If no adapters exist, returns false.
+		*/
+		static bool getMACAddress(MACAddress& address);
+
+		/**
+		* @brief	Queries the internal system performance counter you can use for very precise time
+		* 			measurements. Value is in milliseconds.
+		*
+		* @note	Thread safe.
+		*/
+		static double queryPerformanceTimerMs();
+
+		/**
+		* @brief	Creates a drop target that you can use for tracking OS drag and drop operations performed over
+		* 			a certain area on the specified window.
+		*
+		* @param	window	The window on which to track drop operations.
+		* @param	x	  	The x coordinate of the area to track, relative to window.
+		* @param	y	  	The y coordinate of the area to track, relative to window.
+		* @param	width 	The width of the area to track.
+		* @param	height	The height of the area to track.
+		*
+		* @return	OSDropTarget that you will use to receive all drop data. When no longer needed make sure to destroy it with
+		* 			destroyDropTarget().
+		*/
+		static OSDropTarget& createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height);
+
+		/**
+		* @brief	Destroys a drop target previously created with createDropTarget.
+		*/
+		static void destroyDropTarget(OSDropTarget& target);
+
+		/**
+		* @brief	Message pump. Processes OS messages and returns when it's free.
+		*
+		* @note	Internal method.
+		* 			Core thread only.
+		*/
+		static void _messagePump();
+
+		/**
+		* @brief	Called during application start up from the sim thread.
+		* 			Must be called before any other operations are done.
+		*
+		* @note	Internal method.
+		*/
+		static void _startUp();
+
+		/**
+		* @brief	Called once per frame from the sim thread.
+		*
+		* @note	Internal method.
+		* 			Sim thread only.
+		*/
+		static void _update();
+
+		/**
+		* @brief	Called once per frame from the core thread.
+		*
+		* @note	Internal method.
+		* 			Core thread only.
+		*/
+		static void _coreUpdate();
+
+		/**
+		* @brief	Called during application shut down from the sim thread.
+		*
+		* @note	Internal method.
+		* 			Sim thread only.
+		*/
+		static void _shutDown();
+
+		/**
+		* @brief	Triggered when a pointer leaves the provided window.
+		*
+		* @note	Sim thread only.
+		*/
+		static Event<void(RenderWindowCore*)> onMouseLeftWindow;
+
+		/**
+		* @brief	Triggered whenever the pointer moves.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(const Vector2I&, OSPointerButtonStates)> onCursorMoved;
+
+		/**
+		* @brief	Triggered whenever a pointer button is pressed.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> onCursorButtonPressed;
+
+		/**
+		* @brief	Triggered whenever pointer button is released.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> onCursorButtonReleased;
+
+		/**
+		* @brief	Triggered whenever a pointer button is double clicked.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(const Vector2I&, OSPointerButtonStates)> onCursorDoubleClick;
+
+		/**
+		* @brief	Triggered whenever an input command is entered.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(InputCommandType)> onInputCommand;
+
+		/**
+		* @brief	Triggered whenever the mouse wheel is scolled.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(float)> onMouseWheelScrolled;
+
+		/**
+		* @brief	Triggered whenever a character is entered.
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void(UINT32)> onCharInput;
+
+		/**
+		* @brief	Triggered whenever mouse capture state for the window is changed
+		* 			(it receives or loses it).
+		*
+		* @note	Core thread only.
+		*/
+		static Event<void()> onMouseCaptureChanged;
+	protected:
+		static Pimpl* mData;
+	};
+}

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

@@ -0,0 +1,42 @@
+#include "BsPlatform.h"
+#include "Win32/BsWin32Defs.h"
+#include "Win32/BsWin32DropTarget.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Encapsulate native cursor data so we can avoid including windows.h as it pollutes the global namespace
+	 */
+	struct BS_CORE_EXPORT NativeCursorData
+	{
+		HCURSOR cursor;
+	};
+
+	/**
+	 * @brief	Encapsulate drop target data so we can avoid including windows.h as it pollutes the global namespace
+	 */
+	struct BS_CORE_EXPORT NativeDropTargetData
+	{
+		Map<const RenderWindow*, Win32DropTarget*> dropTargetsPerWindow;
+		Vector<Win32DropTarget*> dropTargetsToInitialize;
+		Vector<Win32DropTarget*> dropTargetsToDestroy;
+	};
+
+	struct Platform::Pimpl
+	{
+		bool mIsCursorHidden = false;
+		NativeCursorData mCursor;
+		bool mUsingCustomCursor = false;
+		Map<const RenderWindowCore*, WindowNonClientAreaData> mNonClientAreas;
+
+		bool mIsTrackingMouse = false;
+		Stack<RenderWindowCore*> mModalWindowStack;
+
+		NativeDropTargetData mDropTargets;
+
+		bool mRequiresStartUp = false;
+		bool mRequiresShutDown = false;
+
+		BS_MUTEX(mSync);
+	};
+}

+ 0 - 350
BansheeCore/Include/Win32/BsPlatformImpl.h

@@ -1,350 +0,0 @@
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsInputFwd.h"
-#include "BsVector2I.h"
-#include "BsRect2I.h"
-#include "BsEvent.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Encapsulate native cursor data so we can avoid including windows.h as it pollutes the global namespace
-	 */
-	struct BS_CORE_EXPORT NativeCursorData
-	{
-		struct Pimpl;
-
-		NativeCursorData();
-		~NativeCursorData();
-
-		Pimpl* data;
-	};
-
-	/**
-	 * @brief	Encapsulate drop target data so we can avoid including windows.h as it pollutes the global namespace
-	 */
-	struct BS_CORE_EXPORT NativeDropTargetData
-	{
-		struct Pimpl;
-
-		NativeDropTargetData();
-		~NativeDropTargetData();
-
-		Pimpl* data;
-	};
-
-	/**
-	 * @brief	Represents a specific non client area used for window resizing.
-	 */
-	struct BS_CORE_EXPORT NonClientResizeArea
-	{
-		NonClientAreaBorderType type;
-		Rect2I area;
-	};
-
-	/**
-	 * @brief	Contains a list of window move and resize non client areas.
-	 */
-	struct BS_CORE_EXPORT WindowNonClientAreaData
-	{
-		Vector<NonClientResizeArea> resizeAreas;
-		Vector<Rect2I> moveAreas;
-	};
-
-	/**
-	 * @brief	Provides access to various Windows operating system functions, including
-	 * 			the main message pump.
-	 */
-	class BS_CORE_EXPORT Platform
-	{
-	public:
-		Platform() { }
-		virtual ~Platform() { }
-
-		/**
-		 * @brief	Retrieves the cursor position in screen coordinates.
-		 * 			
-		 * @note	Thread safe. 
-		 */
-		static Vector2I getCursorPosition();
-
-		/**
-		 * @brief	Moves the cursor to the specified screen position.
-		 * 			
-		 * @note	Thread safe. 
-		 */
-		static void setCursorPosition(const Vector2I& screenPos);
-
-		/**
-		 * @brief	Capture mouse to this window so that we get mouse input even if the mouse leaves the window area.
-		 *
-		 * @note	Thread safe.
-		 */
-		static void captureMouse(const RenderWindow& window);
-		/**
-		 * @brief	Releases the mouse capture set by "captureMouse"
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void releaseMouseCapture();
-
-		/**
-		 * @brief	Checks if provided over screen position is over the specified window.
-		 */
-		static bool isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos);
-
-		/**
-		 * @brief	Limit cursor movement to the specified window.
-		 *
-		 * @note	Thread safe.
-		 */
-		static void clipCursorToWindow(const RenderWindow& window);
-		/**
-		 * @brief	Clip cursor to specific area on the screen.
-		 *
-		 * @note	Thread safe.
-		 */
-		static void clipCursorToRect(const Rect2I& screenRect);
-		/**
-		 * @brief	Disables cursor clipping.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void clipCursorDisable();
-
-		/**
-		 * @brief	Hides the cursor.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void hideCursor();
-		/**
-		 * @brief	Shows the cursor.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void showCursor();
-
-		/**
-		 * @brief	Query if the cursor is hidden.
-		 *
-		 * @note	Thread safe.
-		 */
-		static bool isCursorHidden() { return mIsCursorHidden; }
-		
-		/**
-		 * @brief	Sets a cursor using a custom image.
-		 *
-		 * @param 	pixelData	Cursor image data.
-		 * @param	hotSpot		Offset on the cursor image to where the actual input happens (e.g. tip of the Arrow cursor).
-		 * 						
-		 * @note	Thread safe.
-		 */
-		static void setCursor(PixelData& pixelData, const Vector2I& hotSpot);
-
-		/**
-		 * @brief	Sets custom caption non client areas for the specified window. Using custom client
-		 * 			areas will override window move/drag operation and trigger when user interacts
-		 * 			with the custom area.
-		 * 			
-		 * @note	Thread safe.
-		 * 			All provided areas are relative to the specified window.
-		 * 			Mostly useful for frameless windows that don't have typical caption bar.
-		 */
-		static void setCaptionNonClientAreas(const RenderWindowCore& window, const Vector<Rect2I>& nonClientAreas);
-
-		/**
-		 * @brief	Sets custom non client areas for the specified window. Using custom client
-		 * 			areas will override window resize operation and trigger when user interacts
-		 * 			with the custom area.
-		 * 			
-		 * @note	Thread safe.
-		 * 			All provided areas are relative to the specified window.
-		 * 			Mostly useful for frameless windows that don't have typical border.
-		 */
-		static void setResizeNonClientAreas(const RenderWindowCore& window, const Vector<NonClientResizeArea>& nonClientAreas);
-
-		/**
-		 * @brief	Resets the non client areas for the specified windows and allows 
-		 * 			the platform to use the default values.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void resetNonClientAreas(const RenderWindowCore& window);
-
-		/**
-		 * @brief	Adds a string to the clipboard.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static void copyToClipboard(const WString& string);
-
-		/**
-		 * @brief	Reads a string from the clipboard and returns it. If there is no
-		 * 			string in the clipboard it returns an empty string.
-		 * 			
-		 * @note	Both wide and normal strings will be read, but normal strings will be converted to
-		 * 			a wide string before returning.
-		 * 			
-		 *			Thread safe.
-		 */
-		static WString copyFromClipboard();
-
-		/**
-		 * @brief	Populates the provided buffer with a MAC address of the first available
-		 *			adapter, if one exists. If no adapters exist, returns false.
-		 */
-		static bool getMACAddress(MACAddress& address);
-
-		/**
-		 * @brief	Queries the internal system performance counter you can use for very precise time
-		 * 			measurements. Value is in milliseconds.
-		 * 			
-		 * @note	Thread safe.
-		 */
-		static double queryPerformanceTimerMs();
-
-		/**
-		 * @brief	Creates a drop target that you can use for tracking OS drag and drop operations performed over
-		 * 			a certain area on the specified window.
-		 *
-		 * @param	window	The window on which to track drop operations.
-		 * @param	x	  	The x coordinate of the area to track, relative to window.
-		 * @param	y	  	The y coordinate of the area to track, relative to window.
-		 * @param	width 	The width of the area to track.
-		 * @param	height	The height of the area to track.
-		 *
-		 * @return	OSDropTarget that you will use to receive all drop data. When no longer needed make sure to destroy it with
-		 * 			destroyDropTarget().
-		 */
-		static OSDropTarget& createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height);
-
-		/**
-		 * @brief	Destroys a drop target previously created with createDropTarget.
-		 */
-		static void destroyDropTarget(OSDropTarget& target);
-
-		/**
-		 * @brief	Message pump. Processes OS messages and returns when it's free.
-		 * 			
-		 * @note	Internal method.
-		 * 			Core thread only.
-		 */
-		static void _messagePump();
-
-		/**
-		 * @brief	Called during application start up from the sim thread.
-		 * 			Must be called before any other operations are done.
-		 * 			
-		 * @note	Internal method.
-		 */
-		static void _startUp();
-
-		/**
-		 * @brief	Called once per frame from the sim thread.
-		 * 			
-		 * @note	Internal method.
-		 * 			Sim thread only.
-		 */
-		static void _update();
-
-		/**
-		 * @brief	Called once per frame from the core thread.
-		 * 			
-		 * @note	Internal method.
-		 * 			Core thread only.
-		 */
-		static void _coreUpdate();
-
-		/**
-		 * @brief	Called during application shut down from the sim thread.
-		 * 			
-		 * @note	Internal method.
-		 * 			Sim thread only.
-		 */
-		static void _shutDown();
-
-		/**
-		 * @brief	Triggered when a pointer leaves the provided window.
-		 * 			
-		 * @note	Sim thread only.
-		 */
-		static Event<void(RenderWindowCore*)> onMouseLeftWindow;
-
-		/**
-		 * @brief	Triggered whenever the pointer moves.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(const Vector2I&, OSPointerButtonStates)> onCursorMoved;
-
-		/**
-		 * @brief	Triggered whenever a pointer button is pressed.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> onCursorButtonPressed;
-
-		/**
-		 * @brief	Triggered whenever pointer button is released.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> onCursorButtonReleased;
-
-		/**
-		 * @brief	Triggered whenever a pointer button is double clicked.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(const Vector2I&, OSPointerButtonStates)> onCursorDoubleClick;
-
-		/**
-		 * @brief	Triggered whenever an input command is entered.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(InputCommandType)> onInputCommand;
-
-		/**
-		 * @brief	Triggered whenever the mouse wheel is scolled.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(float)> onMouseWheelScrolled;
-
-		/**
-		 * @brief	Triggered whenever a character is entered.
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void(UINT32)> onCharInput;
-
-		/**
-		 * @brief	Triggered whenever mouse capture state for the window is changed
-		 * 			(it receives or loses it).
-		 * 			
-		 * @note	Core thread only.
-		 */
-		static Event<void()> onMouseCaptureChanged;
-	protected:
-		static bool mIsCursorHidden;
-		static NativeCursorData mCursor;
-		static bool mUsingCustomCursor;
-		static Map<const RenderWindowCore*, WindowNonClientAreaData> mNonClientAreas;
-
-		static bool mIsTrackingMouse;
-		static Stack<RenderWindowCore*> mModalWindowStack;
-
-		static NativeDropTargetData mDropTargets;
-
-		static bool mRequiresStartUp;
-		static bool mRequiresShutDown;
-
-		BS_STATIC_MUTEX(mSync);
-
-		static void win32ShowCursor();
-		static void win32HideCursor();
-	};
-}

+ 0 - 42
BansheeCore/Include/Win32/BsPlatformWndProc.h

@@ -1,42 +0,0 @@
-#pragma once
-
-#include "BsPlatform.h"
-#include "BsWin32Defs.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Contains the main message loop
-	 *
-	 * @note	This is separated from the main Platform because we don't want to include various Windows
-	 * 			defines in a lot of our code that includes "Platform.h".
-	 */
-	class BS_CORE_EXPORT PlatformWndProc : public Platform
-	{
-	public:
-		/**
-		 * @brief	Main message loop callback that processes messages received from windows.
-		 */
-		static LRESULT CALLBACK _win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
-	private:
-		static bool isShiftPressed;
-		static bool isCtrlPressed;
-
-		/**
-		 * @brief	Translate engine non client area to win32 non client area.
-		 */
-		static LRESULT translateNonClientAreaType(NonClientAreaBorderType type);
-
-		/**
-		 * @brief	Method triggerend whenever a mouse event happens.
-		 */
-		static void getMouseData(HWND hWnd, WPARAM wParam, LPARAM lParam, Vector2I& mousePos, OSPointerButtonStates& btnStates);
-
-		/**
-		 * @brief	Converts a virtual key code into an input command, if possible. Returns true
-		 *			if conversion was done.
-		 */
-		static bool getCommand(unsigned int virtualKeyCode, InputCommandType& command);
-	};
-}

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

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "BsPlatform.h"
+#include "BsWin32Defs.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains the main message loop
+	 *
+	 * @note	This is separated from the main Platform because we don't want to include various Windows
+	 * 			defines in a lot of our code that includes "Platform.h".
+	 */
+	class BS_CORE_EXPORT Win32Platform : public Platform
+	{
+	public:
+		/**
+		 * @brief	Main message loop callback that processes messages received from windows.
+		 */
+		static LRESULT CALLBACK _win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+	};
+}

+ 0 - 518
BansheeCore/Source/Win32/BsPlatformImpl.cpp

@@ -1,518 +0,0 @@
-#include "BsPlatform.h"
-#include "BsRenderWindow.h"
-#include "BsPixelUtil.h"
-#include "BsCoreApplication.h"
-#include "BsDebug.h"
-#include "Win32/BsWin32Defs.h"
-#include "Win32/BsWin32DropTarget.h"
-#include <iphlpapi.h>
-
-namespace BansheeEngine
-{
-	Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorMoved;
-	Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonPressed;
-	Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonReleased;
-	Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorDoubleClick;
-	Event<void(InputCommandType)> Platform::onInputCommand;
-	Event<void(float)> Platform::onMouseWheelScrolled;
-	Event<void(UINT32)> Platform::onCharInput;
-
-	Event<void(RenderWindowCore*)> Platform::onMouseLeftWindow;
-	Event<void()> Platform::onMouseCaptureChanged;
-
-	Map<const RenderWindowCore*, WindowNonClientAreaData> Platform::mNonClientAreas;
-	bool Platform::mIsTrackingMouse = false;
-
-	Stack<RenderWindowCore*> Platform::mModalWindowStack;
-
-	NativeDropTargetData Platform::mDropTargets;
-
-	bool Platform::mRequiresStartUp = false;
-	bool Platform::mRequiresShutDown = false;
-
-	BS_STATIC_MUTEX_CLASS_INSTANCE(mSync, Platform);
-
-	struct NativeCursorData::Pimpl
-	{
-		HCURSOR cursor;
-	};
-
-	NativeCursorData::NativeCursorData()
-	{
-		data = bs_new<Pimpl>();
-	}
-
-	NativeCursorData::~NativeCursorData()
-	{
-		bs_delete(data);
-	}
-
-	struct NativeDropTargetData::Pimpl
-	{
-		Map<const RenderWindow*, Win32DropTarget*> dropTargetsPerWindow;
-		Vector<Win32DropTarget*> dropTargetsToInitialize;
-		Vector<Win32DropTarget*> dropTargetsToDestroy;
-	};
-
-	NativeDropTargetData::NativeDropTargetData()
-	{
-		data = bs_new<Pimpl>();
-	}
-
-	NativeDropTargetData::~NativeDropTargetData()
-	{
-		bs_delete(data);
-	}
-
-	bool Platform::mIsCursorHidden = false;
-	NativeCursorData Platform::mCursor;
-	bool Platform::mUsingCustomCursor = false;
-
-	Vector2I Platform::getCursorPosition()
-	{
-		Vector2I screenPos;
-
-		POINT cursorPos;
-		GetCursorPos(&cursorPos);
-
-		screenPos.x = cursorPos.x;
-		screenPos.y = cursorPos.y;
-
-		return screenPos;
-	}
-
-	void Platform::setCursorPosition(const Vector2I& screenPos)
-	{
-		SetCursorPos(screenPos.x, screenPos.y);
-	}
-
-	void Platform::captureMouse(const RenderWindow& window)
-	{
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-		UINT64 hwnd;
-		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
-		
-		PostMessage((HWND)hwnd, WM_BS_SETCAPTURE, WPARAM((HWND)hwnd), 0);
-	}
-
-	void Platform::releaseMouseCapture()
-	{
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-		UINT64 hwnd;
-		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
-
-		PostMessage((HWND)hwnd, WM_BS_RELEASECAPTURE, WPARAM((HWND)hwnd), 0);
-	}
-
-	bool Platform::isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos)
-	{
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-
-		POINT point;
-		point.x = screenPos.x;
-		point.y = screenPos.y;
-
-		UINT64 hwndToCheck;
-		window.getCustomAttribute("WINDOW", &hwndToCheck);
-
-		HWND hwndUnderPos = WindowFromPoint(point);
-		return hwndUnderPos == (HWND)hwndToCheck;
-	}
-
-	void Platform::hideCursor()
-	{
-		mIsCursorHidden = true;
-
-		// ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
-		// WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
-
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-		UINT64 hwnd;
-		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
-
-		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
-	}
-
-	void Platform::showCursor()
-	{
-		mIsCursorHidden = false;
-
-		// ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
-		// WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
-
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-		UINT64 hwnd;
-		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
-
-		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
-	}
-
-	void Platform::clipCursorToWindow(const RenderWindow& window)
-	{
-		UINT64 hwnd;
-		window.getCustomAttribute("WINDOW", &hwnd);
-
-		// Clip cursor to the window
-		RECT clipWindowRect;
-		if(GetWindowRect((HWND)hwnd, &clipWindowRect))
-		{
-			ClipCursor(&clipWindowRect);
-		}
-	}
-
-	void Platform::clipCursorToRect(const Rect2I& screenRect)
-	{
-		RECT clipWindowRect;
-		clipWindowRect.left = screenRect.x;
-		clipWindowRect.top = screenRect.y;
-		clipWindowRect.right = screenRect.x + screenRect.width;
-		clipWindowRect.bottom = screenRect.y + screenRect.height;
-
-		ClipCursor(&clipWindowRect);
-	}
-
-	void Platform::clipCursorDisable()
-	{
-		ClipCursor(NULL);
-	}
-
-	// TODO - Add support for animated custom cursor
-	void Platform::setCursor(PixelData& pixelData, const Vector2I& hotSpot)
-	{
-		if(mUsingCustomCursor)
-		{
-			SetCursor(0);
-			DestroyIcon(mCursor.data->cursor);
-		}
-
-		mUsingCustomCursor = true;
-
-		BITMAPV5HEADER bi;
-
-		ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
-		bi.bV5Size = sizeof(BITMAPV5HEADER);
-		bi.bV5Width = pixelData.getWidth();
-		bi.bV5Height = pixelData.getHeight();
-		bi.bV5Planes = 1;
-		bi.bV5BitCount = 32;
-		bi.bV5Compression = BI_BITFIELDS;
-		bi.bV5RedMask   =  0x00FF0000;
-		bi.bV5GreenMask =  0x0000FF00;
-		bi.bV5BlueMask  =  0x000000FF;
-		bi.bV5AlphaMask =  0xFF000000; 
-
-		HDC hDC = GetDC(NULL);
-
-		void* data = nullptr;
-		HBITMAP hBitmap = CreateDIBSection(hDC, (BITMAPINFO *)&bi, DIB_RGB_COLORS, 
-			(void**)&data, NULL, (DWORD)0);
-
-		HDC hBitmapDC = CreateCompatibleDC(hDC); 
-		ReleaseDC(NULL, hDC);
-
-		// Create an empty mask bitmap.
-		HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, NULL);
-
-		//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);
-				*dst = pixel.getAsBGRA();
-
-				dst++;
-			}
-		}
-
-		SelectObject(hBitmapDC, hOldBitmap);
-
-		DeleteDC(hBitmapDC);
-
-		ICONINFO iconinfo = {0};
-		iconinfo.fIcon = FALSE;
-		iconinfo.xHotspot = (DWORD)hotSpot.x;
-		iconinfo.yHotspot = (DWORD)hotSpot.y;
-		iconinfo.hbmMask = hMonoBitmap;
-		iconinfo.hbmColor = hBitmap;
-
-		mCursor.data->cursor = CreateIconIndirect(&iconinfo);
-
-		DeleteObject(hBitmap);          
-		DeleteObject(hMonoBitmap);
-
-		// Make sure we notify the message loop to perform the actual cursor update
-		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
-		UINT64 hwnd;
-		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
-
-		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
-	}
-
-	void Platform::setCaptionNonClientAreas(const RenderWindowCore& window, const Vector<Rect2I>& nonClientAreas)
-	{
-		BS_LOCK_MUTEX(mSync);
-
-		mNonClientAreas[&window].moveAreas = nonClientAreas;
-	}
-
-	void Platform::setResizeNonClientAreas(const RenderWindowCore& window, const Vector<NonClientResizeArea>& nonClientAreas)
-	{
-		BS_LOCK_MUTEX(mSync);
-
-		mNonClientAreas[&window].resizeAreas = nonClientAreas;
-	}
-
-	void Platform::resetNonClientAreas(const RenderWindowCore& window)
-	{
-		BS_LOCK_MUTEX(mSync);
-
-		auto iterFind = mNonClientAreas.find(&window);
-
-		if(iterFind != end(mNonClientAreas))
-			mNonClientAreas.erase(iterFind);
-	}
-
-	void Platform::copyToClipboard(const WString& string)
-	{
-		HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (string.size() + 1) * sizeof(WString::value_type));
-		WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
-
-		string.copy(buffer, string.size());
-		buffer[string.size()] = '\0';
-
-		GlobalUnlock(hData);
-
-		if(OpenClipboard(NULL))
-		{
-			EmptyClipboard();
-			SetClipboardData(CF_UNICODETEXT, hData);
-			CloseClipboard();
-		}
-		else
-		{
-			GlobalFree(hData);
-		}
-	}
-
-	WString Platform::copyFromClipboard()
-	{
-		if(OpenClipboard(NULL))
-		{
-			HANDLE hData = GetClipboardData(CF_UNICODETEXT);
-
-			if(hData != NULL)
-			{
-				WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
-				WString string(buffer);
-				GlobalUnlock(hData);
-
-				CloseClipboard();
-				return string;
-			}
-			else
-			{
-				CloseClipboard();
-				return L"";
-			}			
-		}
-
-		return L"";
-	}
-
-	bool Platform::getMACAddress(MACAddress& address)
-	{
-		std::memset(&address, 0, sizeof(address));
-
-		PIP_ADAPTER_INFO adapterInfo = bs_alloc<IP_ADAPTER_INFO>();
-		
-		ULONG len = sizeof(IP_ADAPTER_INFO);
-		DWORD rc = GetAdaptersInfo(adapterInfo, &len);
-
-		if (rc == ERROR_BUFFER_OVERFLOW)
-		{
-			bs_free(adapterInfo);
-			adapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(bs_alloc(len));
-		}
-		else if (rc != ERROR_SUCCESS)
-		{
-			bs_free(adapterInfo);
-			return false;
-		}
-
-		if (GetAdaptersInfo(adapterInfo, &len) == NO_ERROR)
-		{
-			PIP_ADAPTER_INFO curAdapter = nullptr;
-			curAdapter = adapterInfo;
-
-			while (curAdapter)
-			{
-				if (curAdapter->Type == MIB_IF_TYPE_ETHERNET && curAdapter->AddressLength == sizeof(address))
-				{
-					std::memcpy(&address, curAdapter->Address, curAdapter->AddressLength);
-					return true;
-				}
-
-				curAdapter = curAdapter->Next;
-			}
-		}
-
-		bs_free(adapterInfo);
-		return false;
-	}
-
-	double Platform::queryPerformanceTimerMs()
-	{
-		LARGE_INTEGER counterValue;
-		QueryPerformanceCounter(&counterValue);
-		
-		LARGE_INTEGER counterFreq;
-		QueryPerformanceFrequency(&counterFreq);
-
-		return (double)counterValue.QuadPart / (counterFreq.QuadPart * 0.001);
-	}
-
-	OSDropTarget& Platform::createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height)
-	{
-		Win32DropTarget* win32DropTarget = nullptr;
-		auto iterFind = mDropTargets.data->dropTargetsPerWindow.find(window);
-		if(iterFind == mDropTargets.data->dropTargetsPerWindow.end())
-		{
-			UINT64 hwnd;
-			window->getCustomAttribute("WINDOW", &hwnd);
-
-			win32DropTarget = bs_new<Win32DropTarget>((HWND)hwnd);
-			mDropTargets.data->dropTargetsPerWindow[window] = win32DropTarget;
-
-			{
-				BS_LOCK_MUTEX(mSync);
-				mDropTargets.data->dropTargetsToInitialize.push_back(win32DropTarget);
-			}
-		}
-		else
-			win32DropTarget = iterFind->second;
-
-		OSDropTarget* newDropTarget = new (bs_alloc<OSDropTarget>()) OSDropTarget(window, x, y, width, height);
-		win32DropTarget->registerDropTarget(newDropTarget);
-
-		return *newDropTarget;
-	}
-
-	void Platform::destroyDropTarget(OSDropTarget& target)
-	{
-		auto iterFind = mDropTargets.data->dropTargetsPerWindow.find(target.getOwnerWindow());
-		if(iterFind == mDropTargets.data->dropTargetsPerWindow.end())
-		{
-			LOGWRN("Attempting to destroy a drop target but cannot find its parent window.");
-		}
-		else
-		{
-			Win32DropTarget* win32DropTarget = iterFind->second;
-			win32DropTarget->unregisterDropTarget(&target);
-
-			if(win32DropTarget->getNumDropTargets() == 0)
-			{
-				mDropTargets.data->dropTargetsPerWindow.erase(iterFind);
-
-				{
-					BS_LOCK_MUTEX(mSync);
-					mDropTargets.data->dropTargetsToDestroy.push_back(win32DropTarget);
-				}
-			}
-		}
-		
-		BS_PVT_DELETE(OSDropTarget, &target);
-	}
-
-	void Platform::_messagePump()
-	{
-		MSG  msg;
-		while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
-		{
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
-		}
-	}
-
-	void Platform::_startUp()
-	{
-		BS_LOCK_MUTEX(mSync);
-
-		mRequiresStartUp = true;
-	}
-
-	void Platform::_update()
-	{
-		for(auto& dropTarget : mDropTargets.data->dropTargetsPerWindow)
-		{
-			dropTarget.second->update();
-		}
-	}
-
-	void Platform::_coreUpdate()
-	{
-		{
-			BS_LOCK_MUTEX(mSync);
-			if(mRequiresStartUp)
-			{
-				OleInitialize(nullptr);
-
-				mRequiresStartUp = false;
-			}
-		}
-
-		{
-			BS_LOCK_MUTEX(mSync);
-			for(auto& dropTargetToInit : mDropTargets.data->dropTargetsToInitialize)
-			{
-				dropTargetToInit->registerWithOS();
-			}
-
-			mDropTargets.data->dropTargetsToInitialize.clear();
-		}
-
-		{
-			BS_LOCK_MUTEX(mSync);
-			for(auto& dropTargetToDestroy : mDropTargets.data->dropTargetsToDestroy)
-			{
-				dropTargetToDestroy->unregisterWithOS();
-				dropTargetToDestroy->Release();
-			}
-
-			mDropTargets.data->dropTargetsToDestroy.clear();
-		}
-
-		_messagePump();
-
-		{
-			BS_LOCK_MUTEX(mSync);
-			if(mRequiresShutDown)
-			{
-				OleUninitialize();
-				mRequiresShutDown = false;
-			}
-		}
-	}
-
-	void Platform::_shutDown()
-	{
-		BS_LOCK_MUTEX(mSync);
-
-		mRequiresShutDown = true;
-	}
-
-	void Platform::win32ShowCursor()
-	{
-		SetCursor(mCursor.data->cursor);
-	}
-
-	void Platform::win32HideCursor()
-	{
-		SetCursor(nullptr);
-	}
-}

+ 0 - 584
BansheeCore/Source/Win32/BsPlatformWndProc.cpp

@@ -1,584 +0,0 @@
-#include "Win32/BsPlatformWndProc.h"
-#include "BsRenderWindow.h"
-#include "BsCoreApplication.h"
-#include "BsInput.h"
-#include "BsDebug.h"
-#include "BsRenderWindowManager.h"
-
-namespace BansheeEngine
-{
-	bool PlatformWndProc::isShiftPressed = false;
-	bool PlatformWndProc::isCtrlPressed = false;
-
-	LRESULT CALLBACK PlatformWndProc::_win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-	{
-		if (uMsg == WM_CREATE)
-		{	// Store pointer to Win32Window in user data area
-			SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams));
-
-			RenderWindowCore* newWindow = (RenderWindowCore*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
-			if(newWindow->getProperties().isModal())
-			{
-				if(!mModalWindowStack.empty())
-				{
-					RenderWindowCore* curModalWindow = mModalWindowStack.top();
-
-					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);
-					}
-				}
-
-				mModalWindowStack.push(newWindow);
-			}
-
-			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_ACTIVATE:
-			{
-				bool active = (LOWORD(wParam) != WA_INACTIVE);
-				if( active )
-					win->setActive(true);
-
-				break;
-			}
-		case WM_DESTROY:
-			{
-				bool reenableWindows = false;
-				if(!mModalWindowStack.empty())
-				{
-					if(mModalWindowStack.top() == win) // This is the most common case, top-most modal was closed
-					{
-						mModalWindowStack.pop();
-					}
-					else // Possibly some other window was closed somehow, see if it was modal and remove from stack if it is
-					{
-						Stack<RenderWindowCore*> newStack;
-
-						while(!mModalWindowStack.empty())
-						{
-							RenderWindowCore* curWindow = mModalWindowStack.top();
-							mModalWindowStack.pop();
-
-							if(curWindow == win)
-								continue;
-
-							newStack.push(curWindow);
-						}
-
-						mModalWindowStack = newStack;
-					}
-
-					if(!mModalWindowStack.empty()) // Enable next modal window
-					{
-						RenderWindowCore* curModalWindow = mModalWindowStack.top();
-
-						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);
-					}
-				}
-
-				break;
-			}
-		case WM_SETFOCUS:
-			{
-				if (!win->getProperties().hasFocus())
-					win->_windowFocusReceived();
-
-				break;
-			}
-		case WM_KILLFOCUS:
-			{
-				if (win->getProperties().hasFocus())
-					win->_windowFocusLost();
-
-				break;
-			}
-		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;
-		case WM_MOVE:
-			win->_windowMovedOrResized();
-			break;
-		case WM_DISPLAYCHANGE:
-			win->_windowMovedOrResized();
-			break;
-		case WM_SIZE:
-			win->_windowMovedOrResized();
-
-			if (wParam == SIZE_MAXIMIZED)
-				win->_notifyMaximized();
-			else if (wParam == SIZE_MINIMIZED)
-				win->_notifyMinimized();
-			else if (wParam == SIZE_RESTORED)
-				win->_notifyRestored();
-
-			break;
-		case WM_SETCURSOR:
-			if(isCursorHidden())
-				win32HideCursor();
-			else
-			{
-				switch (LOWORD(lParam))
-				{
-				case HTTOPLEFT:
-					SetCursor(LoadCursor(0, IDC_SIZENWSE));
-					return 0;
-				case HTTOP:
-					SetCursor(LoadCursor(0, IDC_SIZENS));
-					return 0;
-				case HTTOPRIGHT:
-					SetCursor(LoadCursor(0, IDC_SIZENESW));
-					return 0;
-				case HTLEFT:
-					SetCursor(LoadCursor(0, IDC_SIZEWE));
-					return 0;
-				case HTRIGHT:
-					SetCursor(LoadCursor(0, IDC_SIZEWE));
-					return 0;
-				case HTBOTTOMLEFT:
-					SetCursor(LoadCursor(0, IDC_SIZENESW));
-					return 0;
-				case HTBOTTOM:
-					SetCursor(LoadCursor(0, IDC_SIZENS));
-					return 0;
-				case HTBOTTOMRIGHT:
-					SetCursor(LoadCursor(0, IDC_SIZENWSE));
-					return 0;
-				}
-
-				win32ShowCursor();
-			}
-			return true;
-		case WM_GETMINMAXINFO:
-		{
-			// Prevent the window from going smaller than some minimu size
-			((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
-			((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
-
-			// Ensure maximizes window has proper size and doesn't cover the entire screen
-			const POINT ptZero = { 0, 0 };
-			HMONITOR primaryMonitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
-
-			MONITORINFO monitorInfo;
-			monitorInfo.cbSize = sizeof(MONITORINFO);
-			GetMonitorInfo(primaryMonitor, &monitorInfo);
-
-			((MINMAXINFO*)lParam)->ptMaxPosition.x = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
-			((MINMAXINFO*)lParam)->ptMaxPosition.y = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
-			((MINMAXINFO*)lParam)->ptMaxSize.x = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
-			((MINMAXINFO*)lParam)->ptMaxSize.y = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
-		}
-			break;
-		case WM_CLOSE:
-			{
-				gCoreApplication().stopMainLoop();
-
-				return 0;
-			}
-		case WM_NCHITTEST:
-			{
-				auto iterFind = mNonClientAreas.find(win);
-				if(iterFind == mNonClientAreas.end())
-					break;
-
-				POINT mousePos;
-				mousePos.x = GET_X_LPARAM(lParam);
-				mousePos.y = GET_Y_LPARAM(lParam); 
-
-				ScreenToClient(hWnd, &mousePos);
-
-				Vector2I mousePosInt;
-				mousePosInt.x = mousePos.x;
-				mousePosInt.y = mousePos.y;
-
-				Vector<NonClientResizeArea>& resizeAreasPerWindow = iterFind->second.resizeAreas;
-				for(auto area : resizeAreasPerWindow)
-				{
-					if(area.area.contains(mousePosInt))
-						return translateNonClientAreaType(area.type);
-				}
-
-				Vector<Rect2I>& moveAreasPerWindow = iterFind->second.moveAreas;
-				for(auto area : moveAreasPerWindow)
-				{
-					if(area.contains(mousePosInt))
-						return HTCAPTION;
-				}
-
-				return HTCLIENT;
-			}
-		case WM_NCLBUTTONDBLCLK:
-			// Maximize/Restore on double-click
-			if (wParam == HTCAPTION)
-			{
-				WINDOWPLACEMENT windowPlacement;
-				windowPlacement.length = sizeof(WINDOWPLACEMENT);
-				GetWindowPlacement(hWnd, &windowPlacement);
-
-				if (windowPlacement.showCmd == SW_MAXIMIZE)
-					ShowWindow(hWnd, SW_RESTORE);
-				else
-					ShowWindow(hWnd, SW_MAXIMIZE);
-
-				return 0;
-			}
-			break;
-		case WM_MOUSELEAVE:
-			{
-				// Note: Right now I track only mouse leaving client area. So it's possible for the "mouse left window" callback
-				// to trigger, while the mouse is still in the non-client area of the window.
-				mIsTrackingMouse = false; // TrackMouseEvent ends when this message is received and needs to be re-applied
-
-				BS_LOCK_MUTEX(mSync);
-
-				if (!onMouseLeftWindow.empty())
-					onMouseLeftWindow(win);
-			}
-			break;
-		case WM_LBUTTONUP:
-			{
-				ReleaseCapture();
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonReleased.empty())
-					onCursorButtonReleased(intMousePos, OSMouseButton::Left, btnStates);
-			}
-			break;
-		case WM_MBUTTONUP:
-			{
-				ReleaseCapture();
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonReleased.empty())
-					onCursorButtonReleased(intMousePos, OSMouseButton::Middle, btnStates);
-			}
-			break;
-		case WM_RBUTTONUP:
-			{
-				ReleaseCapture();
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonReleased.empty())
-					onCursorButtonReleased(intMousePos, OSMouseButton::Right, btnStates);
-			}
-			break;
-		case WM_LBUTTONDOWN:
-			{
-				SetCapture(hWnd);
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonPressed.empty())
-					onCursorButtonPressed(intMousePos, OSMouseButton::Left, btnStates);
-			}
-			break;
-		case WM_MBUTTONDOWN:
-			{
-				SetCapture(hWnd);
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonPressed.empty())
-					onCursorButtonPressed(intMousePos, OSMouseButton::Middle, btnStates);
-			}
-			break;
-		case WM_RBUTTONDOWN:
-			{
-				SetCapture(hWnd);
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorButtonPressed.empty())
-					onCursorButtonPressed(intMousePos, OSMouseButton::Right, btnStates);
-			}
-			break;
-		case WM_LBUTTONDBLCLK:
-			{
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorDoubleClick.empty())
-					onCursorDoubleClick(intMousePos, btnStates);
-			}
-			break;
-		case WM_NCMOUSEMOVE:
-		case WM_MOUSEMOVE:
-			{
-				// Set up tracking so we get notified when mouse leaves the window
-				if(!mIsTrackingMouse)
-				{
-					TRACKMOUSEEVENT tme = { sizeof(tme) };
-					tme.dwFlags = TME_LEAVE;
-
-					tme.hwndTrack = hWnd;
-					TrackMouseEvent(&tme);
-
-					mIsTrackingMouse = true;
-				}
-
-				if(uMsg == WM_NCMOUSEMOVE)
-					return true;
-
-				Vector2I intMousePos;
-				OSPointerButtonStates btnStates;
-				
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
-
-				if(!onCursorMoved.empty())
-					onCursorMoved(intMousePos, btnStates);
-
-				return true;
-			}
-		case WM_MOUSEWHEEL:
-			{
-				INT16 wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);
-
-				float wheelDeltaFlt = wheelDelta / (float)WHEEL_DELTA;
-				if(!onMouseWheelScrolled.empty())
-					onMouseWheelScrolled(wheelDeltaFlt);
-
-				return true;
-			}
-		case WM_SYSKEYDOWN:
-		case WM_KEYDOWN:
-			{
-				if(wParam == VK_SHIFT)
-				{
-					isShiftPressed = true;
-					break;
-				}
-
-				if(wParam == VK_CONTROL)
-				{
-					isCtrlPressed = true;
-					break;
-				}
-
-				InputCommandType command = InputCommandType::Backspace;
-				if(getCommand((unsigned int)wParam, command))
-				{
-					if(!onInputCommand.empty())
-						onInputCommand(command);
-
-					return 0;
-				}
-
-				break;
-			}
-		case WM_SYSKEYUP:
-		case WM_KEYUP:
-			{
-				if(wParam == VK_SHIFT)
-				{
-					isShiftPressed = false;
-				}
-
-				if(wParam == VK_CONTROL)
-				{
-					isCtrlPressed = false;
-				}
-
-				break;
-			}
-		case WM_CHAR:
-			{
-				// TODO - Not handling IME input
-
-				switch (wParam) 
-				{ 
-				case VK_BACK:
-				case 0x0A:  // linefeed 
-				case 0x0D:  // carriage return 
-				case VK_ESCAPE:
-				case VK_TAB: 
-					break; 
-				default:    // displayable character 
-					{
-						UINT8 scanCode = (lParam >> 16) & 0xFF;
-
-						BYTE keyState[256];
-						HKL layout = GetKeyboardLayout(0);
-						if(GetKeyboardState(keyState) == 0)
-							return 0;
-
-						unsigned int vk = MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, layout);
-						if(vk == 0)
-							return 0;
-
-						InputCommandType command = InputCommandType::Backspace;
-						if(getCommand(vk, command)) // We ignore character combinations that are special commands
-							return 0;
-
-						UINT32 finalChar = (UINT32)wParam;
-
-						if(!onCharInput.empty())
-							onCharInput(finalChar);
-
-						return 0;
-					}
-				} 
-
-				break;
-			}
-		case WM_BS_SETCAPTURE:
-			SetCapture(hWnd);
-			break;
-		case WM_BS_RELEASECAPTURE:
-			ReleaseCapture();
-			break;
-		case WM_CAPTURECHANGED:
-			if(!onMouseCaptureChanged.empty())
-				onMouseCaptureChanged();
-			break;
-		}
-
-		return DefWindowProc( hWnd, uMsg, wParam, lParam );
-	}
-
-	LRESULT PlatformWndProc::translateNonClientAreaType(NonClientAreaBorderType type)
-	{
-		LRESULT dir = HTCLIENT;
-		switch(type)
-		{
-		case NonClientAreaBorderType::Left:
-			dir = HTLEFT;
-			break;
-		case NonClientAreaBorderType::TopLeft:
-			dir = HTTOPLEFT;
-			break;
-		case NonClientAreaBorderType::Top:
-			dir = HTTOP;
-			break;
-		case NonClientAreaBorderType::TopRight:
-			dir = HTTOPRIGHT;
-			break;
-		case NonClientAreaBorderType::Right:
-			dir = HTRIGHT;
-			break;
-		case NonClientAreaBorderType::BottomRight:
-			dir = HTBOTTOMRIGHT;
-			break;
-		case NonClientAreaBorderType::Bottom:
-			dir = HTBOTTOM;
-			break;
-		case NonClientAreaBorderType::BottomLeft:
-			dir = HTBOTTOMLEFT;
-			break;
-		}
-
-		return dir;
-	}
-
-	void PlatformWndProc::getMouseData(HWND hWnd, WPARAM wParam, LPARAM lParam, Vector2I& mousePos, OSPointerButtonStates& btnStates)
-	{
-		POINT clientPoint;
-
-		clientPoint.x = GET_X_LPARAM(lParam);
-		clientPoint.y = GET_Y_LPARAM(lParam); 
-
-		ClientToScreen(hWnd, &clientPoint);
-
-		mousePos.x = clientPoint.x;
-		mousePos.y = clientPoint.y;
-
-		btnStates.mouseButtons[0] = (wParam & MK_LBUTTON) != 0;
-		btnStates.mouseButtons[1] = (wParam & MK_MBUTTON) != 0;
-		btnStates.mouseButtons[2] = (wParam & MK_RBUTTON) != 0;
-		btnStates.shift = (wParam & MK_SHIFT) != 0;
-		btnStates.ctrl = (wParam & MK_CONTROL) != 0;
-	}
-
-	bool PlatformWndProc::getCommand(unsigned int virtualKeyCode, InputCommandType& command)
-	{
-		switch (virtualKeyCode) 
-		{ 
-		case VK_LEFT:
-			command = isShiftPressed ? InputCommandType::SelectLeft : InputCommandType::CursorMoveLeft;
-			return true;
-		case VK_RIGHT:
-			command = isShiftPressed ? InputCommandType::SelectRight : InputCommandType::CursorMoveRight;
-			return true;
-		case VK_UP:
-			command = isShiftPressed ? InputCommandType::SelectUp : InputCommandType::CursorMoveUp;
-			return true;
-		case VK_DOWN:
-			command = isShiftPressed ? InputCommandType::SelectDown : InputCommandType::CursorMoveDown;
-			return true;
-		case VK_ESCAPE:
-			command = InputCommandType::Escape;
-			return true;
-		case VK_RETURN:
-			command = InputCommandType::Return;
-			return true;
-		case VK_BACK:
-			command = InputCommandType::Backspace;
-			return true;
-		case VK_DELETE:
-			command = InputCommandType::Delete;
-			return true;
-		}
-
-		return false;
-	}
-}

+ 1060 - 0
BansheeCore/Source/Win32/BsWin32Platform.cpp

@@ -0,0 +1,1060 @@
+#include "Win32/BsWin32Platform.h"
+#include "BsRenderWindow.h"
+#include "BsPixelUtil.h"
+#include "BsCoreApplication.h"
+#include "BsDebug.h"
+#include "BsRenderWindowManager.h"
+#include "Win32/BsWin32Defs.h"
+#include "Win32/BsWin32DropTarget.h"
+#include "Win32/BsWin32PlatformData.h"
+#include <iphlpapi.h>
+
+namespace BansheeEngine
+{
+	Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorMoved;
+	Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonPressed;
+	Event<void(const Vector2I&, OSMouseButton button, OSPointerButtonStates)> Platform::onCursorButtonReleased;
+	Event<void(const Vector2I&, OSPointerButtonStates)> Platform::onCursorDoubleClick;
+	Event<void(InputCommandType)> Platform::onInputCommand;
+	Event<void(float)> Platform::onMouseWheelScrolled;
+	Event<void(UINT32)> Platform::onCharInput;
+
+	Event<void(RenderWindowCore*)> Platform::onMouseLeftWindow;
+	Event<void()> Platform::onMouseCaptureChanged;
+
+	Platform::Pimpl* Platform::mData = bs_new<Platform::Pimpl>();
+
+	Platform::~Platform()
+	{
+		bs_delete(mData);
+		mData = nullptr;
+	}
+
+	Vector2I Platform::getCursorPosition()
+	{
+		Vector2I screenPos;
+
+		POINT cursorPos;
+		GetCursorPos(&cursorPos);
+
+		screenPos.x = cursorPos.x;
+		screenPos.y = cursorPos.y;
+
+		return screenPos;
+	}
+
+	void Platform::setCursorPosition(const Vector2I& screenPos)
+	{
+		SetCursorPos(screenPos.x, screenPos.y);
+	}
+
+	void Platform::captureMouse(const RenderWindow& window)
+	{
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+		UINT64 hwnd;
+		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
+		
+		PostMessage((HWND)hwnd, WM_BS_SETCAPTURE, WPARAM((HWND)hwnd), 0);
+	}
+
+	void Platform::releaseMouseCapture()
+	{
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+		UINT64 hwnd;
+		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
+
+		PostMessage((HWND)hwnd, WM_BS_RELEASECAPTURE, WPARAM((HWND)hwnd), 0);
+	}
+
+	bool Platform::isPointOverWindow(const RenderWindow& window, const Vector2I& screenPos)
+	{
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+
+		POINT point;
+		point.x = screenPos.x;
+		point.y = screenPos.y;
+
+		UINT64 hwndToCheck;
+		window.getCustomAttribute("WINDOW", &hwndToCheck);
+
+		HWND hwndUnderPos = WindowFromPoint(point);
+		return hwndUnderPos == (HWND)hwndToCheck;
+	}
+
+	void Platform::hideCursor()
+	{
+		mData->mIsCursorHidden = true;
+
+		// ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
+		// WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
+
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+		UINT64 hwnd;
+		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
+
+		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
+	}
+
+	void Platform::showCursor()
+	{
+		mData->mIsCursorHidden = false;
+
+		// ShowCursor(FALSE) doesn't work. Presumably because we're in the wrong thread, and using
+		// WM_SETCURSOR in message loop to hide the cursor is smarter solution anyway.
+
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+		UINT64 hwnd;
+		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
+
+		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
+	}
+
+	bool Platform::isCursorHidden() 
+	{ 
+		return mData->mIsCursorHidden; 
+	}
+
+	void Platform::clipCursorToWindow(const RenderWindow& window)
+	{
+		UINT64 hwnd;
+		window.getCustomAttribute("WINDOW", &hwnd);
+
+		// Clip cursor to the window
+		RECT clipWindowRect;
+		if(GetWindowRect((HWND)hwnd, &clipWindowRect))
+		{
+			ClipCursor(&clipWindowRect);
+		}
+	}
+
+	void Platform::clipCursorToRect(const Rect2I& screenRect)
+	{
+		RECT clipWindowRect;
+		clipWindowRect.left = screenRect.x;
+		clipWindowRect.top = screenRect.y;
+		clipWindowRect.right = screenRect.x + screenRect.width;
+		clipWindowRect.bottom = screenRect.y + screenRect.height;
+
+		ClipCursor(&clipWindowRect);
+	}
+
+	void Platform::clipCursorDisable()
+	{
+		ClipCursor(NULL);
+	}
+
+	// TODO - Add support for animated custom cursor
+	void Platform::setCursor(PixelData& pixelData, const Vector2I& hotSpot)
+	{
+		if (mData->mUsingCustomCursor)
+		{
+			SetCursor(0);
+			DestroyIcon(mData->mCursor.cursor);
+		}
+
+		mData->mUsingCustomCursor = true;
+
+		BITMAPV5HEADER bi;
+
+		ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
+		bi.bV5Size = sizeof(BITMAPV5HEADER);
+		bi.bV5Width = pixelData.getWidth();
+		bi.bV5Height = pixelData.getHeight();
+		bi.bV5Planes = 1;
+		bi.bV5BitCount = 32;
+		bi.bV5Compression = BI_BITFIELDS;
+		bi.bV5RedMask   =  0x00FF0000;
+		bi.bV5GreenMask =  0x0000FF00;
+		bi.bV5BlueMask  =  0x000000FF;
+		bi.bV5AlphaMask =  0xFF000000; 
+
+		HDC hDC = GetDC(NULL);
+
+		void* data = nullptr;
+		HBITMAP hBitmap = CreateDIBSection(hDC, (BITMAPINFO *)&bi, DIB_RGB_COLORS, 
+			(void**)&data, NULL, (DWORD)0);
+
+		HDC hBitmapDC = CreateCompatibleDC(hDC); 
+		ReleaseDC(NULL, hDC);
+
+		// Create an empty mask bitmap.
+		HBITMAP hMonoBitmap = CreateBitmap(pixelData.getWidth(), pixelData.getHeight(), 1, 1, NULL);
+
+		//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);
+				*dst = pixel.getAsBGRA();
+
+				dst++;
+			}
+		}
+
+		SelectObject(hBitmapDC, hOldBitmap);
+
+		DeleteDC(hBitmapDC);
+
+		ICONINFO iconinfo = {0};
+		iconinfo.fIcon = FALSE;
+		iconinfo.xHotspot = (DWORD)hotSpot.x;
+		iconinfo.yHotspot = (DWORD)hotSpot.y;
+		iconinfo.hbmMask = hMonoBitmap;
+		iconinfo.hbmColor = hBitmap;
+
+		mData->mCursor.cursor = CreateIconIndirect(&iconinfo);
+
+		DeleteObject(hBitmap);          
+		DeleteObject(hMonoBitmap);
+
+		// Make sure we notify the message loop to perform the actual cursor update
+		RenderWindowPtr primaryWindow = gCoreApplication().getPrimaryWindow();
+		UINT64 hwnd;
+		primaryWindow->getCustomAttribute("WINDOW", &hwnd);
+
+		PostMessage((HWND)hwnd, WM_SETCURSOR, WPARAM((HWND)hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
+	}
+
+	void Platform::setCaptionNonClientAreas(const RenderWindowCore& window, const Vector<Rect2I>& nonClientAreas)
+	{
+		BS_LOCK_MUTEX(mData->mSync);
+
+		mData->mNonClientAreas[&window].moveAreas = nonClientAreas;
+	}
+
+	void Platform::setResizeNonClientAreas(const RenderWindowCore& window, const Vector<NonClientResizeArea>& nonClientAreas)
+	{
+		BS_LOCK_MUTEX(mData->mSync);
+
+		mData->mNonClientAreas[&window].resizeAreas = nonClientAreas;
+	}
+
+	void Platform::resetNonClientAreas(const RenderWindowCore& window)
+	{
+		BS_LOCK_MUTEX(mData->mSync);
+
+		auto iterFind = mData->mNonClientAreas.find(&window);
+
+		if (iterFind != end(mData->mNonClientAreas))
+			mData->mNonClientAreas.erase(iterFind);
+	}
+
+	void Platform::copyToClipboard(const WString& string)
+	{
+		HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (string.size() + 1) * sizeof(WString::value_type));
+		WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
+
+		string.copy(buffer, string.size());
+		buffer[string.size()] = '\0';
+
+		GlobalUnlock(hData);
+
+		if(OpenClipboard(NULL))
+		{
+			EmptyClipboard();
+			SetClipboardData(CF_UNICODETEXT, hData);
+			CloseClipboard();
+		}
+		else
+		{
+			GlobalFree(hData);
+		}
+	}
+
+	WString Platform::copyFromClipboard()
+	{
+		if(OpenClipboard(NULL))
+		{
+			HANDLE hData = GetClipboardData(CF_UNICODETEXT);
+
+			if(hData != NULL)
+			{
+				WString::value_type* buffer = (WString::value_type*)GlobalLock(hData);
+				WString string(buffer);
+				GlobalUnlock(hData);
+
+				CloseClipboard();
+				return string;
+			}
+			else
+			{
+				CloseClipboard();
+				return L"";
+			}			
+		}
+
+		return L"";
+	}
+
+	bool Platform::getMACAddress(MACAddress& address)
+	{
+		std::memset(&address, 0, sizeof(address));
+
+		PIP_ADAPTER_INFO adapterInfo = bs_alloc<IP_ADAPTER_INFO>();
+		
+		ULONG len = sizeof(IP_ADAPTER_INFO);
+		DWORD rc = GetAdaptersInfo(adapterInfo, &len);
+
+		if (rc == ERROR_BUFFER_OVERFLOW)
+		{
+			bs_free(adapterInfo);
+			adapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(bs_alloc(len));
+		}
+		else if (rc != ERROR_SUCCESS)
+		{
+			bs_free(adapterInfo);
+			return false;
+		}
+
+		if (GetAdaptersInfo(adapterInfo, &len) == NO_ERROR)
+		{
+			PIP_ADAPTER_INFO curAdapter = nullptr;
+			curAdapter = adapterInfo;
+
+			while (curAdapter)
+			{
+				if (curAdapter->Type == MIB_IF_TYPE_ETHERNET && curAdapter->AddressLength == sizeof(address))
+				{
+					std::memcpy(&address, curAdapter->Address, curAdapter->AddressLength);
+					return true;
+				}
+
+				curAdapter = curAdapter->Next;
+			}
+		}
+
+		bs_free(adapterInfo);
+		return false;
+	}
+
+	double Platform::queryPerformanceTimerMs()
+	{
+		LARGE_INTEGER counterValue;
+		QueryPerformanceCounter(&counterValue);
+		
+		LARGE_INTEGER counterFreq;
+		QueryPerformanceFrequency(&counterFreq);
+
+		return (double)counterValue.QuadPart / (counterFreq.QuadPart * 0.001);
+	}
+
+	OSDropTarget& Platform::createDropTarget(const RenderWindow* window, int x, int y, unsigned int width, unsigned int height)
+	{
+		Win32DropTarget* win32DropTarget = nullptr;
+		auto iterFind = mData->mDropTargets.dropTargetsPerWindow.find(window);
+		if (iterFind == mData->mDropTargets.dropTargetsPerWindow.end())
+		{
+			UINT64 hwnd;
+			window->getCustomAttribute("WINDOW", &hwnd);
+
+			win32DropTarget = bs_new<Win32DropTarget>((HWND)hwnd);
+			mData->mDropTargets.dropTargetsPerWindow[window] = win32DropTarget;
+
+			{
+				BS_LOCK_MUTEX(mData->mSync);
+				mData->mDropTargets.dropTargetsToInitialize.push_back(win32DropTarget);
+			}
+		}
+		else
+			win32DropTarget = iterFind->second;
+
+		OSDropTarget* newDropTarget = new (bs_alloc<OSDropTarget>()) OSDropTarget(window, x, y, width, height);
+		win32DropTarget->registerDropTarget(newDropTarget);
+
+		return *newDropTarget;
+	}
+
+	void Platform::destroyDropTarget(OSDropTarget& target)
+	{
+		auto iterFind = mData->mDropTargets.dropTargetsPerWindow.find(target.getOwnerWindow());
+		if (iterFind == mData->mDropTargets.dropTargetsPerWindow.end())
+		{
+			LOGWRN("Attempting to destroy a drop target but cannot find its parent window.");
+		}
+		else
+		{
+			Win32DropTarget* win32DropTarget = iterFind->second;
+			win32DropTarget->unregisterDropTarget(&target);
+
+			if(win32DropTarget->getNumDropTargets() == 0)
+			{
+				mData->mDropTargets.dropTargetsPerWindow.erase(iterFind);
+
+				{
+					BS_LOCK_MUTEX(mData->mSync);
+					mData->mDropTargets.dropTargetsToDestroy.push_back(win32DropTarget);
+				}
+			}
+		}
+		
+		BS_PVT_DELETE(OSDropTarget, &target);
+	}
+
+	void Platform::_messagePump()
+	{
+		MSG  msg;
+		while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
+		{
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+		}
+	}
+
+	void Platform::_startUp()
+	{
+		BS_LOCK_MUTEX(mData->mSync);
+
+		mData->mRequiresStartUp = true;
+	}
+
+	void Platform::_update()
+	{
+		for (auto& dropTarget : mData->mDropTargets.dropTargetsPerWindow)
+		{
+			dropTarget.second->update();
+		}
+	}
+
+	void Platform::_coreUpdate()
+	{
+		{
+			BS_LOCK_MUTEX(mData->mSync);
+			if (mData->mRequiresStartUp)
+			{
+				OleInitialize(nullptr);
+
+				mData->mRequiresStartUp = false;
+			}
+		}
+
+		{
+			BS_LOCK_MUTEX(mData->mSync);
+			for (auto& dropTargetToInit : mData->mDropTargets.dropTargetsToInitialize)
+			{
+				dropTargetToInit->registerWithOS();
+			}
+
+			mData->mDropTargets.dropTargetsToInitialize.clear();
+		}
+
+		{
+			BS_LOCK_MUTEX(mData->mSync);
+			for (auto& dropTargetToDestroy : mData->mDropTargets.dropTargetsToDestroy)
+			{
+				dropTargetToDestroy->unregisterWithOS();
+				dropTargetToDestroy->Release();
+			}
+
+			mData->mDropTargets.dropTargetsToDestroy.clear();
+		}
+
+		_messagePump();
+
+		{
+			BS_LOCK_MUTEX(mData->mSync);
+			if (mData->mRequiresShutDown)
+			{
+				OleUninitialize();
+				mData->mRequiresShutDown = false;
+			}
+		}
+	}
+
+	void Platform::_shutDown()
+	{
+		BS_LOCK_MUTEX(mData->mSync);
+
+		mData->mRequiresShutDown = true;
+	}
+
+	bool isShiftPressed = false;
+	bool isCtrlPressed = false;
+
+	/**
+	 * @brief	Translate engine non client area to win32 non client area.
+	 */
+	LRESULT translateNonClientAreaType(NonClientAreaBorderType type)
+	{
+		LRESULT dir = HTCLIENT;
+		switch(type)
+		{
+		case NonClientAreaBorderType::Left:
+			dir = HTLEFT;
+			break;
+		case NonClientAreaBorderType::TopLeft:
+			dir = HTTOPLEFT;
+			break;
+		case NonClientAreaBorderType::Top:
+			dir = HTTOP;
+			break;
+		case NonClientAreaBorderType::TopRight:
+			dir = HTTOPRIGHT;
+			break;
+		case NonClientAreaBorderType::Right:
+			dir = HTRIGHT;
+			break;
+		case NonClientAreaBorderType::BottomRight:
+			dir = HTBOTTOMRIGHT;
+			break;
+		case NonClientAreaBorderType::Bottom:
+			dir = HTBOTTOM;
+			break;
+		case NonClientAreaBorderType::BottomLeft:
+			dir = HTBOTTOMLEFT;
+			break;
+		}
+
+		return dir;
+	}
+
+	/**
+	 * @brief	Method triggered whenever a mouse event happens.
+	 */
+	void getMouseData(HWND hWnd, WPARAM wParam, LPARAM lParam, Vector2I& mousePos, OSPointerButtonStates& btnStates)
+	{
+		POINT clientPoint;
+
+		clientPoint.x = GET_X_LPARAM(lParam);
+		clientPoint.y = GET_Y_LPARAM(lParam); 
+
+		ClientToScreen(hWnd, &clientPoint);
+
+		mousePos.x = clientPoint.x;
+		mousePos.y = clientPoint.y;
+
+		btnStates.mouseButtons[0] = (wParam & MK_LBUTTON) != 0;
+		btnStates.mouseButtons[1] = (wParam & MK_MBUTTON) != 0;
+		btnStates.mouseButtons[2] = (wParam & MK_RBUTTON) != 0;
+		btnStates.shift = (wParam & MK_SHIFT) != 0;
+		btnStates.ctrl = (wParam & MK_CONTROL) != 0;
+	}
+
+	/**
+	 * @brief	Converts a virtual key code into an input command, if possible. Returns true
+	 *			if conversion was done.
+	 */
+	bool getCommand(unsigned int virtualKeyCode, InputCommandType& command)
+	{
+		switch (virtualKeyCode) 
+		{ 
+		case VK_LEFT:
+			command = isShiftPressed ? InputCommandType::SelectLeft : InputCommandType::CursorMoveLeft;
+			return true;
+		case VK_RIGHT:
+			command = isShiftPressed ? InputCommandType::SelectRight : InputCommandType::CursorMoveRight;
+			return true;
+		case VK_UP:
+			command = isShiftPressed ? InputCommandType::SelectUp : InputCommandType::CursorMoveUp;
+			return true;
+		case VK_DOWN:
+			command = isShiftPressed ? InputCommandType::SelectDown : InputCommandType::CursorMoveDown;
+			return true;
+		case VK_ESCAPE:
+			command = InputCommandType::Escape;
+			return true;
+		case VK_RETURN:
+			command = InputCommandType::Return;
+			return true;
+		case VK_BACK:
+			command = InputCommandType::Backspace;
+			return true;
+		case VK_DELETE:
+			command = InputCommandType::Delete;
+			return true;
+		}
+
+		return false;
+	}
+
+	LRESULT CALLBACK Win32Platform::_win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+	{
+		if (uMsg == WM_CREATE)
+		{	// Store pointer to Win32Window in user data area
+			SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams));
+
+			RenderWindowCore* newWindow = (RenderWindowCore*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+			if(newWindow->getProperties().isModal())
+			{
+				if(!mData->mModalWindowStack.empty())
+				{
+					RenderWindowCore* curModalWindow = mData->mModalWindowStack.top();
+
+					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(newWindow);
+			}
+
+			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_ACTIVATE:
+			{
+				bool active = (LOWORD(wParam) != WA_INACTIVE);
+				if( active )
+					win->setActive(true);
+
+				break;
+			}
+		case WM_DESTROY:
+			{
+				bool reenableWindows = false;
+				if (!mData->mModalWindowStack.empty())
+				{
+					if (mData->mModalWindowStack.top() == win) // This is the most common case, top-most modal was closed
+					{
+						mData->mModalWindowStack.pop();
+					}
+					else // Possibly some other window was closed somehow, see if it was modal and remove from stack if it is
+					{
+						Stack<RenderWindowCore*> newStack;
+
+						while (!mData->mModalWindowStack.empty())
+						{
+							RenderWindowCore* curWindow = mData->mModalWindowStack.top();
+							mData->mModalWindowStack.pop();
+
+							if(curWindow == win)
+								continue;
+
+							newStack.push(curWindow);
+						}
+
+						mData->mModalWindowStack = newStack;
+					}
+
+					if (!mData->mModalWindowStack.empty()) // Enable next modal window
+					{
+						RenderWindowCore* curModalWindow = mData->mModalWindowStack.top();
+
+						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);
+					}
+				}
+
+				break;
+			}
+		case WM_SETFOCUS:
+			{
+				if (!win->getProperties().hasFocus())
+					win->_windowFocusReceived();
+
+				break;
+			}
+		case WM_KILLFOCUS:
+			{
+				if (win->getProperties().hasFocus())
+					win->_windowFocusLost();
+
+				break;
+			}
+		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;
+		case WM_MOVE:
+			win->_windowMovedOrResized();
+			break;
+		case WM_DISPLAYCHANGE:
+			win->_windowMovedOrResized();
+			break;
+		case WM_SIZE:
+			win->_windowMovedOrResized();
+
+			if (wParam == SIZE_MAXIMIZED)
+				win->_notifyMaximized();
+			else if (wParam == SIZE_MINIMIZED)
+				win->_notifyMinimized();
+			else if (wParam == SIZE_RESTORED)
+				win->_notifyRestored();
+
+			break;
+		case WM_SETCURSOR:
+			if(isCursorHidden())
+				SetCursor(nullptr);
+			else
+			{
+				switch (LOWORD(lParam))
+				{
+				case HTTOPLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZENWSE));
+					return 0;
+				case HTTOP:
+					SetCursor(LoadCursor(0, IDC_SIZENS));
+					return 0;
+				case HTTOPRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZENESW));
+					return 0;
+				case HTLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZEWE));
+					return 0;
+				case HTRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZEWE));
+					return 0;
+				case HTBOTTOMLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZENESW));
+					return 0;
+				case HTBOTTOM:
+					SetCursor(LoadCursor(0, IDC_SIZENS));
+					return 0;
+				case HTBOTTOMRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZENWSE));
+					return 0;
+				}
+
+				SetCursor(mData->mCursor.cursor);
+			}
+			return true;
+		case WM_GETMINMAXINFO:
+		{
+			// Prevent the window from going smaller than some minimu size
+			((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
+			((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
+
+			// Ensure maximizes window has proper size and doesn't cover the entire screen
+			const POINT ptZero = { 0, 0 };
+			HMONITOR primaryMonitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
+
+			MONITORINFO monitorInfo;
+			monitorInfo.cbSize = sizeof(MONITORINFO);
+			GetMonitorInfo(primaryMonitor, &monitorInfo);
+
+			((MINMAXINFO*)lParam)->ptMaxPosition.x = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
+			((MINMAXINFO*)lParam)->ptMaxPosition.y = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
+			((MINMAXINFO*)lParam)->ptMaxSize.x = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
+			((MINMAXINFO*)lParam)->ptMaxSize.y = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
+		}
+			break;
+		case WM_CLOSE:
+			{
+				gCoreApplication().stopMainLoop();
+
+				return 0;
+			}
+		case WM_NCHITTEST:
+			{
+				auto iterFind = mData->mNonClientAreas.find(win);
+				if (iterFind == mData->mNonClientAreas.end())
+					break;
+
+				POINT mousePos;
+				mousePos.x = GET_X_LPARAM(lParam);
+				mousePos.y = GET_Y_LPARAM(lParam); 
+
+				ScreenToClient(hWnd, &mousePos);
+
+				Vector2I mousePosInt;
+				mousePosInt.x = mousePos.x;
+				mousePosInt.y = mousePos.y;
+
+				Vector<NonClientResizeArea>& resizeAreasPerWindow = iterFind->second.resizeAreas;
+				for(auto area : resizeAreasPerWindow)
+				{
+					if(area.area.contains(mousePosInt))
+						return translateNonClientAreaType(area.type);
+				}
+
+				Vector<Rect2I>& moveAreasPerWindow = iterFind->second.moveAreas;
+				for(auto area : moveAreasPerWindow)
+				{
+					if(area.contains(mousePosInt))
+						return HTCAPTION;
+				}
+
+				return HTCLIENT;
+			}
+		case WM_NCLBUTTONDBLCLK:
+			// Maximize/Restore on double-click
+			if (wParam == HTCAPTION)
+			{
+				WINDOWPLACEMENT windowPlacement;
+				windowPlacement.length = sizeof(WINDOWPLACEMENT);
+				GetWindowPlacement(hWnd, &windowPlacement);
+
+				if (windowPlacement.showCmd == SW_MAXIMIZE)
+					ShowWindow(hWnd, SW_RESTORE);
+				else
+					ShowWindow(hWnd, SW_MAXIMIZE);
+
+				return 0;
+			}
+			break;
+		case WM_MOUSELEAVE:
+			{
+				// Note: Right now I track only mouse leaving client area. So it's possible for the "mouse left window" callback
+				// to trigger, while the mouse is still in the non-client area of the window.
+				mData->mIsTrackingMouse = false; // TrackMouseEvent ends when this message is received and needs to be re-applied
+
+				BS_LOCK_MUTEX(mData->mSync);
+
+				if (!onMouseLeftWindow.empty())
+					onMouseLeftWindow(win);
+			}
+			break;
+		case WM_LBUTTONUP:
+			{
+				ReleaseCapture();
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonReleased.empty())
+					onCursorButtonReleased(intMousePos, OSMouseButton::Left, btnStates);
+			}
+			break;
+		case WM_MBUTTONUP:
+			{
+				ReleaseCapture();
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonReleased.empty())
+					onCursorButtonReleased(intMousePos, OSMouseButton::Middle, btnStates);
+			}
+			break;
+		case WM_RBUTTONUP:
+			{
+				ReleaseCapture();
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonReleased.empty())
+					onCursorButtonReleased(intMousePos, OSMouseButton::Right, btnStates);
+			}
+			break;
+		case WM_LBUTTONDOWN:
+			{
+				SetCapture(hWnd);
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonPressed.empty())
+					onCursorButtonPressed(intMousePos, OSMouseButton::Left, btnStates);
+			}
+			break;
+		case WM_MBUTTONDOWN:
+			{
+				SetCapture(hWnd);
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonPressed.empty())
+					onCursorButtonPressed(intMousePos, OSMouseButton::Middle, btnStates);
+			}
+			break;
+		case WM_RBUTTONDOWN:
+			{
+				SetCapture(hWnd);
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorButtonPressed.empty())
+					onCursorButtonPressed(intMousePos, OSMouseButton::Right, btnStates);
+			}
+			break;
+		case WM_LBUTTONDBLCLK:
+			{
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorDoubleClick.empty())
+					onCursorDoubleClick(intMousePos, btnStates);
+			}
+			break;
+		case WM_NCMOUSEMOVE:
+		case WM_MOUSEMOVE:
+			{
+				// Set up tracking so we get notified when mouse leaves the window
+				if(!mData->mIsTrackingMouse)
+				{
+					TRACKMOUSEEVENT tme = { sizeof(tme) };
+					tme.dwFlags = TME_LEAVE;
+
+					tme.hwndTrack = hWnd;
+					TrackMouseEvent(&tme);
+
+					mData->mIsTrackingMouse = true;
+				}
+
+				if(uMsg == WM_NCMOUSEMOVE)
+					return true;
+
+				Vector2I intMousePos;
+				OSPointerButtonStates btnStates;
+				
+				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+
+				if(!onCursorMoved.empty())
+					onCursorMoved(intMousePos, btnStates);
+
+				return true;
+			}
+		case WM_MOUSEWHEEL:
+			{
+				INT16 wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);
+
+				float wheelDeltaFlt = wheelDelta / (float)WHEEL_DELTA;
+				if(!onMouseWheelScrolled.empty())
+					onMouseWheelScrolled(wheelDeltaFlt);
+
+				return true;
+			}
+		case WM_SYSKEYDOWN:
+		case WM_KEYDOWN:
+			{
+				if(wParam == VK_SHIFT)
+				{
+					isShiftPressed = true;
+					break;
+				}
+
+				if(wParam == VK_CONTROL)
+				{
+					isCtrlPressed = true;
+					break;
+				}
+
+				InputCommandType command = InputCommandType::Backspace;
+				if(getCommand((unsigned int)wParam, command))
+				{
+					if(!onInputCommand.empty())
+						onInputCommand(command);
+
+					return 0;
+				}
+
+				break;
+			}
+		case WM_SYSKEYUP:
+		case WM_KEYUP:
+			{
+				if(wParam == VK_SHIFT)
+				{
+					isShiftPressed = false;
+				}
+
+				if(wParam == VK_CONTROL)
+				{
+					isCtrlPressed = false;
+				}
+
+				break;
+			}
+		case WM_CHAR:
+			{
+				// TODO - Not handling IME input
+
+				switch (wParam) 
+				{ 
+				case VK_BACK:
+				case 0x0A:  // linefeed 
+				case 0x0D:  // carriage return 
+				case VK_ESCAPE:
+				case VK_TAB: 
+					break; 
+				default:    // displayable character 
+					{
+						UINT8 scanCode = (lParam >> 16) & 0xFF;
+
+						BYTE keyState[256];
+						HKL layout = GetKeyboardLayout(0);
+						if(GetKeyboardState(keyState) == 0)
+							return 0;
+
+						unsigned int vk = MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, layout);
+						if(vk == 0)
+							return 0;
+
+						InputCommandType command = InputCommandType::Backspace;
+						if(getCommand(vk, command)) // We ignore character combinations that are special commands
+							return 0;
+
+						UINT32 finalChar = (UINT32)wParam;
+
+						if(!onCharInput.empty())
+							onCharInput(finalChar);
+
+						return 0;
+					}
+				} 
+
+				break;
+			}
+		case WM_BS_SETCAPTURE:
+			SetCapture(hWnd);
+			break;
+		case WM_BS_RELEASECAPTURE:
+			ReleaseCapture();
+			break;
+		case WM_CAPTURECHANGED:
+			if(!onMouseCaptureChanged.empty())
+				onMouseCaptureChanged();
+			break;
+		}
+
+		return DefWindowProc( hWnd, uMsg, wParam, lParam );
+	}
+}

+ 2 - 2
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -1,6 +1,6 @@
 #include "BsD3D11RenderWindow.h"
 #include "BsCoreThread.h"
-#include "Win32/BsPlatformWndProc.h"
+#include "Win32/BsWin32Platform.h"
 #include "BsD3D11RenderAPI.h"
 #include "BsD3D11Device.h"
 #include "BsD3D11RenderTexture.h"
@@ -228,7 +228,7 @@ namespace BansheeEngine
 
 			// Register the window class
 			// Allow 4 bytes of window data for D3D11RenderWindow pointer
-			WNDCLASS wc = { classStyle, PlatformWndProc::_win32WndProc, 0, 0, hInst,
+			WNDCLASS wc = { classStyle, Win32Platform::_win32WndProc, 0, 0, hInst,
 				LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
 				(HBRUSH)GetStockObject(BLACK_BRUSH), 0, "D3D11Wnd" };
 

+ 2 - 2
BansheeD3D9RenderSystem/Source/BsD3D9RenderWindow.cpp

@@ -6,7 +6,7 @@
 #include "BsD3D9RenderAPI.h"
 #include "BsRenderAPI.h"
 #include "BsBitwise.h"
-#include "Win32/BsPlatformWndProc.h"
+#include "Win32/BsWin32Platform.h"
 #include "BsD3D9VideoModeInfo.h"
 #include "BsD3D9DeviceManager.h"
 #include "BsRenderWindowManager.h"
@@ -203,7 +203,7 @@ namespace BansheeEngine
 
 
 			// Register the window class
-			WNDCLASS wc = { 0, PlatformWndProc::_win32WndProc, 0, 0, hInst,
+			WNDCLASS wc = { 0, Win32Platform::_win32WndProc, 0, 0, hInst,
 				LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
 				(HBRUSH)GetStockObject(BLACK_BRUSH), 0, "D3D9Wnd" };
 			RegisterClass(&wc);

+ 2 - 2
BansheeGLRenderSystem/Source/BsWin32Window.cpp

@@ -9,7 +9,7 @@
 #include "BsException.h"
 #include "BsWin32GLSupport.h"
 #include "BsWin32Context.h"
-#include "Win32/BsPlatformWndProc.h"
+#include "Win32/BsWin32Platform.h"
 #include "BsWin32VideoModeInfo.h"
 #include "BsGLPixelFormat.h"
 #include "BsRenderWindowManager.h"
@@ -255,7 +255,7 @@ namespace BansheeEngine
 			}
 
 			// register class and create window
-			WNDCLASS wc = { CS_OWNDC, PlatformWndProc::_win32WndProc, 0, 0, hInst,
+			WNDCLASS wc = { CS_OWNDC, Win32Platform::_win32WndProc, 0, 0, hInst,
 				LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
 				(HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "GLWindow" };
 			RegisterClass(&wc);