Browse Source

Worker core thread accessors are now submitted before the main one so resources are properly updated before they're used
Fixed a potential issue where toggling a mouse button on and off during a single frame wouldn't register a mouse click (helps when frames are really long)
Changed how render window syncing works so that it doesn't happen that older data overwrites newer data
Fixed selection rendering so it doesn't activate a frame too late

Marko Pintera 10 years ago
parent
commit
9277fddd48

+ 9 - 1
BansheeCore/Include/BsCoreApplication.h

@@ -50,10 +50,17 @@ namespace BansheeEngine
 			void stopMainLoop();
 			void stopMainLoop();
 
 
 			/**
 			/**
-			 * @brief	
+			 * @brief	Returns the main window that was created on application start-up.
 			 */
 			 */
 			RenderWindowPtr getPrimaryWindow() const { return mPrimaryWindow; }
 			RenderWindowPtr getPrimaryWindow() const { return mPrimaryWindow; }
 
 
+			/**
+			 * @brief	Returns the id of the simulation thread.
+			 *
+			 * @note	Thread safe.
+			 */
+			BS_THREAD_ID_TYPE getSimThreadId() { return mSimThreadId; }
+
 			/**
 			/**
 			 * @brief	Loads a plugin.
 			 * @brief	Loads a plugin.
 			 *
 			 *
@@ -113,6 +120,7 @@ namespace BansheeEngine
 		bool mIsFrameRenderingFinished;
 		bool mIsFrameRenderingFinished;
 		BS_MUTEX(mFrameRenderingFinishedMutex);
 		BS_MUTEX(mFrameRenderingFinishedMutex);
 		BS_THREAD_SYNCHRONISER(mFrameRenderingFinishedCondition);
 		BS_THREAD_SYNCHRONISER(mFrameRenderingFinishedCondition);
+		BS_THREAD_ID_TYPE mSimThreadId;
 
 
 		volatile bool mRunMainLoop;
 		volatile bool mRunMainLoop;
 	};
 	};

+ 2 - 0
BansheeCore/Include/BsCoreThread.h

@@ -30,6 +30,7 @@ namespace BansheeEngine
 		struct AccessorContainer
 		struct AccessorContainer
 		{
 		{
 			CoreAccessorPtr accessor;
 			CoreAccessorPtr accessor;
+			bool isMain;
 		};
 		};
 
 
 public:
 public:
@@ -120,6 +121,7 @@ private:
 	volatile bool mCoreThreadShutdown;
 	volatile bool mCoreThreadShutdown;
 
 
 	HThread mCoreThread;
 	HThread mCoreThread;
+	BS_THREAD_ID_TYPE mSimThreadId;
 	BS_THREAD_ID_TYPE mCoreThreadId;
 	BS_THREAD_ID_TYPE mCoreThreadId;
 	BS_MUTEX(mCommandQueueMutex)
 	BS_MUTEX(mCommandQueueMutex)
 	BS_MUTEX(mAccessorMutex)
 	BS_MUTEX(mAccessorMutex)

+ 2 - 1
BansheeCore/Include/BsInput.h

@@ -26,7 +26,8 @@ namespace BansheeEngine
 			Off, /**< Button is not being pressed. */
 			Off, /**< Button is not being pressed. */
 			On, /**< Button is being pressed. */
 			On, /**< Button is being pressed. */
 			ToggledOn, /**< Button has been pressed this frame. */
 			ToggledOn, /**< Button has been pressed this frame. */
-			ToggledOff /**< Button has been released this frame. */
+			ToggledOff, /**< Button has been released this frame. */
+			ToggledOnOff, /**< Button has been pressed and released this frame. */
 		};
 		};
 
 
 		/**
 		/**

+ 10 - 13
BansheeCore/Include/BsRenderWindow.h

@@ -234,19 +234,22 @@ namespace BansheeEngine
 	protected:
 	protected:
 		friend class RenderWindow;
 		friend class RenderWindow;
 		friend class RenderWindowManager;
 		friend class RenderWindowManager;
+		friend class RenderWindowCoreManager;
 
 
 		/**
 		/**
-		 * @copydoc	CoreObjectCore::syncToCore
+		 * @brief	Returns window properties that are always kept in sync between core and sim threads.
+		 *
+		 * @note	Used for keeping up what are the most up to date settings.
 		 */
 		 */
-		virtual void syncToCore(const CoreSyncData& data);
+		virtual RenderWindowProperties& getSyncedProperties() = 0;
 
 
 		/**
 		/**
-		 * @brief	Retrieves data that is to be used for syncing between core and sim thread
-		 *			versions of this object.
+		 * @brief	Updates window properties from the synced property data.
 		 */
 		 */
-		virtual UINT32 getSyncData(UINT8* buffer) { return 0; }
+		virtual void syncProperties() = 0;
 
 
 		RENDER_WINDOW_DESC mDesc;
 		RENDER_WINDOW_DESC mDesc;
+		SpinLock mLock;
 	};
 	};
 
 
 	/**
 	/**
@@ -353,21 +356,15 @@ namespace BansheeEngine
 		 */
 		 */
 		RenderWindowProperties& getMutableProperties();
 		RenderWindowProperties& getMutableProperties();
 
 
-		/**
-		 * @brief	Updates internal properties using the provided data. Data must have been retrieved from
-		 *			"getSyncData" method of the core version of this object.
-		 */
-		virtual void setSyncData(UINT8* buffer, UINT32 size) { }
-
 		/**
 		/**
 		 * @copydoc	RenderTarget::createCore
 		 * @copydoc	RenderTarget::createCore
 		 */
 		 */
 		SPtr<CoreObjectCore> createCore() const;
 		SPtr<CoreObjectCore> createCore() const;
 
 
 		/**
 		/**
-		 * @copydoc	CoreObjectCore::syncToCore
+		 * @brief	Updates window properties from the synced property data.
 		 */
 		 */
-		virtual CoreSyncData syncToCore(FrameAlloc* allocator);
+		virtual void syncProperties() = 0;
 
 
 	protected:
 	protected:
 		RENDER_WINDOW_DESC mDesc;
 		RENDER_WINDOW_DESC mDesc;

+ 16 - 18
BansheeCore/Include/BsRenderWindowManager.h

@@ -14,16 +14,6 @@ namespace BansheeEngine
 	 */
 	 */
 	class BS_CORE_EXPORT RenderWindowManager : public Module<RenderWindowManager>
 	class BS_CORE_EXPORT RenderWindowManager : public Module<RenderWindowManager>
 	{
 	{
-		/**
-		 * @brief	Holds a buffer that contains dirty data used for updating sim
-		 *			thread render windows after changes on the core thread.
-		 */
-		struct DirtyPropertyData
-		{
-			UINT8* data;
-			UINT32 size;
-		};
-
 		/**
 		/**
 		 * @brief	Holds information about a window that was moved or resized.
 		 * @brief	Holds information about a window that was moved or resized.
 		 */
 		 */
@@ -72,9 +62,9 @@ namespace BansheeEngine
 		void notifyMovedOrResized(RenderWindowCore* window);
 		void notifyMovedOrResized(RenderWindowCore* window);
 
 
 		/**
 		/**
-		 * @brief	Called by the core thread when window properties change.
+		 * @brief	Called by the sim thread when window properties change.
 		 */
 		 */
-		void notifyPropertiesDirty(RenderWindowCore* window);
+		void notifySyncDataDirty(RenderWindowCore* coreWindow);
 
 
 		/**
 		/**
 		 * @brief	Returns a list of all open render windows.
 		 * @brief	Returns a list of all open render windows.
@@ -108,11 +98,6 @@ namespace BansheeEngine
 		 */
 		 */
 		RenderWindow* getNonCore(const RenderWindowCore* window) const;
 		RenderWindow* getNonCore(const RenderWindowCore* window) const;
 
 
-		/**
-		 * @brief	Adds a new dirty property entry.
-		 */
-		void setDirtyProperties(RenderWindowCore* coreWindow);
-
 		/**
 		/**
 		 * @copydoc	create
 		 * @copydoc	create
 		 */
 		 */
@@ -127,7 +112,7 @@ namespace BansheeEngine
 		RenderWindow* mNewWindowInFocus;
 		RenderWindow* mNewWindowInFocus;
 		Vector<MoveOrResizeData> mMovedOrResizedWindows;
 		Vector<MoveOrResizeData> mMovedOrResizedWindows;
 		Vector<RenderWindow*> mMouseLeftWindows;
 		Vector<RenderWindow*> mMouseLeftWindows;
-		Map<RenderWindow*, DirtyPropertyData> mDirtyProperties;
+		UnorderedSet<RenderWindow*> mDirtyProperties;
 	};
 	};
 
 
 	/**
 	/**
@@ -143,6 +128,18 @@ namespace BansheeEngine
 		 */
 		 */
 		SPtr<RenderWindowCore> create(RENDER_WINDOW_DESC& desc);
 		SPtr<RenderWindowCore> create(RENDER_WINDOW_DESC& desc);
 
 
+		/**
+		 * @brief	Called once per frame. Dispatches events.
+		 * 
+		 * @note	Internal method.
+		 */
+		void _update();
+
+		/**
+		 * @brief	Called by the core thread when window properties change.
+		 */
+		void notifySyncDataDirty(RenderWindowCore* window);
+
 		/**
 		/**
 		 * @brief	Returns a list of all open render windows.
 		 * @brief	Returns a list of all open render windows.
 		 */
 		 */
@@ -169,5 +166,6 @@ namespace BansheeEngine
 
 
 		BS_MUTEX(mWindowMutex);
 		BS_MUTEX(mWindowMutex);
 		Vector<RenderWindowCore*> mCreatedWindows;
 		Vector<RenderWindowCore*> mCreatedWindows;
+		UnorderedSet<RenderWindowCore*> mDirtyProperties;
 	};
 	};
 }
 }

+ 2 - 1
BansheeCore/Source/BsCoreApplication.cpp

@@ -60,7 +60,7 @@ namespace BansheeEngine
 
 
 	CoreApplication::CoreApplication(START_UP_DESC& desc)
 	CoreApplication::CoreApplication(START_UP_DESC& desc)
 		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
 		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
-		mRendererPlugin(nullptr)
+		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID)
 	{
 	{
 		signal(SIGABRT, handleAbort);
 		signal(SIGABRT, handleAbort);
 
 
@@ -184,6 +184,7 @@ namespace BansheeEngine
 			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
 			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
 
 
 			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
 			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
+			gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
 			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
 			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
 
 
 			// Update plugins
 			// Update plugins

+ 18 - 3
BansheeCore/Source/BsCoreThread.cpp

@@ -2,6 +2,7 @@
 #include "BsThreadPool.h"
 #include "BsThreadPool.h"
 #include "BsTaskScheduler.h"
 #include "BsTaskScheduler.h"
 #include "BsFrameAlloc.h"
 #include "BsFrameAlloc.h"
+#include "BsCoreApplication.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
@@ -22,7 +23,8 @@ namespace BansheeEngine
 			mFrameAllocs[i]->setOwnerThread(BS_THREAD_CURRENT_ID); // Sim thread
 			mFrameAllocs[i]->setOwnerThread(BS_THREAD_CURRENT_ID); // Sim thread
 		}
 		}
 
 
-		mCoreThreadId = BS_THREAD_CURRENT_ID;
+		mSimThreadId = BS_THREAD_CURRENT_ID;
+		mCoreThreadId = mSimThreadId; // For now
 		mCommandQueue = bs_new<CommandQueue<CommandQueueSync>>(BS_THREAD_CURRENT_ID);
 		mCommandQueue = bs_new<CommandQueue<CommandQueueSync>>(BS_THREAD_CURRENT_ID);
 
 
 		initCoreThread();
 		initCoreThread();
@@ -131,6 +133,7 @@ namespace BansheeEngine
 			CoreAccessorPtr newAccessor = bs_shared_ptr<CoreThreadAccessor<CommandQueueNoSync>>(BS_THREAD_CURRENT_ID);
 			CoreAccessorPtr newAccessor = bs_shared_ptr<CoreThreadAccessor<CommandQueueNoSync>>(BS_THREAD_CURRENT_ID);
 			mAccessor = bs_new<AccessorContainer>();
 			mAccessor = bs_new<AccessorContainer>();
 			mAccessor->accessor = newAccessor;
 			mAccessor->accessor = newAccessor;
+			mAccessor->isMain = BS_THREAD_CURRENT_ID == mSimThreadId;
 
 
 			BS_LOCK_MUTEX(mAccessorMutex);
 			BS_LOCK_MUTEX(mAccessorMutex);
 			mAccessors.push_back(mAccessor);
 			mAccessors.push_back(mAccessor);
@@ -154,9 +157,21 @@ namespace BansheeEngine
 			accessorCopies = mAccessors;
 			accessorCopies = mAccessors;
 		}
 		}
 
 
-		for(auto& accessor : accessorCopies)
-			accessor->accessor->submitToCoreThread(blockUntilComplete);
+		// Submit workers first
+		AccessorContainer* mainAccessor = nullptr;
+		for (auto& accessor : accessorCopies)
+		{
+			if (!accessor->isMain)
+				accessor->accessor->submitToCoreThread(blockUntilComplete);
+			else
+				mainAccessor = accessor;
+		}
+
+		// Then main
+		if (mainAccessor != nullptr)
+			mainAccessor->accessor->submitToCoreThread(blockUntilComplete);
 
 
+		// Then synced
 		mSyncedCoreAccessor->submitToCoreThread(blockUntilComplete);
 		mSyncedCoreAccessor->submitToCoreThread(blockUntilComplete);
 	}
 	}
 
 

+ 22 - 10
BansheeCore/Source/BsInput.cpp

@@ -64,7 +64,7 @@ namespace BansheeEngine
 		{
 		{
 			for (UINT32 i = 0; i < BC_Count; i++)
 			for (UINT32 i = 0; i < BC_Count; i++)
 			{
 			{
-				if (deviceData.keyStates[i] == ButtonState::ToggledOff)
+				if (deviceData.keyStates[i] == ButtonState::ToggledOff || deviceData.keyStates[i] == ButtonState::ToggledOnOff)
 					deviceData.keyStates[i] = ButtonState::Off;
 					deviceData.keyStates[i] = ButtonState::Off;
 				else if (deviceData.keyStates[i] == ButtonState::ToggledOn)
 				else if (deviceData.keyStates[i] == ButtonState::ToggledOn)
 					deviceData.keyStates[i] = ButtonState::On;
 					deviceData.keyStates[i] = ButtonState::On;
@@ -73,7 +73,7 @@ namespace BansheeEngine
 
 
 		for (UINT32 i = 0; i < 3; i++)
 		for (UINT32 i = 0; i < 3; i++)
 		{
 		{
-			if (mPointerButtonStates[i] == ButtonState::ToggledOff)
+			if (mPointerButtonStates[i] == ButtonState::ToggledOff || mPointerButtonStates[i] == ButtonState::ToggledOnOff)
 				mPointerButtonStates[i] = ButtonState::Off;
 				mPointerButtonStates[i] = ButtonState::Off;
 			else if (mPointerButtonStates[i] == ButtonState::ToggledOn)
 			else if (mPointerButtonStates[i] == ButtonState::ToggledOn)
 				mPointerButtonStates[i] = ButtonState::On;
 				mPointerButtonStates[i] = ButtonState::On;
@@ -131,7 +131,10 @@ namespace BansheeEngine
 		while (deviceIdx >= (UINT32)mDevices.size())
 		while (deviceIdx >= (UINT32)mDevices.size())
 			mDevices.push_back(DeviceData());
 			mDevices.push_back(DeviceData());
 
 
-		mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOff;
+		if (mDevices[deviceIdx].keyStates[code & 0x0000FFFF] == ButtonState::ToggledOn)
+			mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOnOff;
+		else
+			mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOff;
 
 
 		if(!onButtonUp.empty())
 		if(!onButtonUp.empty())
 		{
 		{
@@ -178,7 +181,10 @@ namespace BansheeEngine
 
 
 	void Input::cursorReleased(const PointerEvent& event)
 	void Input::cursorReleased(const PointerEvent& event)
 	{
 	{
-		mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOff;
+		if (mPointerButtonStates[(UINT32)event.button] == ButtonState::ToggledOn)
+			mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOnOff;
+		else
+			mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOff;
 
 
 		if(!onPointerReleased.empty())
 		if(!onPointerReleased.empty())
 			onPointerReleased(event);
 			onPointerReleased(event);
@@ -227,7 +233,8 @@ namespace BansheeEngine
 			return false;
 			return false;
 
 
 		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::On || 
 		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::On || 
-			mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn;
+			mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn ||
+			mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isButtonUp(ButtonCode button, UINT32 deviceIdx) const
 	bool Input::isButtonUp(ButtonCode button, UINT32 deviceIdx) const
@@ -235,7 +242,8 @@ namespace BansheeEngine
 		if (deviceIdx >= (UINT32)mDevices.size())
 		if (deviceIdx >= (UINT32)mDevices.size())
 			return false;
 			return false;
 
 
-		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOff;
+		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOff ||
+			mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isButtonDown(ButtonCode button, UINT32 deviceIdx) const
 	bool Input::isButtonDown(ButtonCode button, UINT32 deviceIdx) const
@@ -243,23 +251,27 @@ namespace BansheeEngine
 		if (deviceIdx >= (UINT32)mDevices.size())
 		if (deviceIdx >= (UINT32)mDevices.size())
 			return false;
 			return false;
 
 
-		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn;
+		return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn ||
+			mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isPointerButtonHeld(PointerEventButton pointerButton) const
 	bool Input::isPointerButtonHeld(PointerEventButton pointerButton) const
 	{
 	{
 		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::On ||
 		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::On ||
-			mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn;
+			mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn ||
+			mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isPointerButtonUp(PointerEventButton pointerButton) const
 	bool Input::isPointerButtonUp(PointerEventButton pointerButton) const
 	{
 	{
-		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOff;
+		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOff ||
+			mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isPointerButtonDown(PointerEventButton pointerButton) const
 	bool Input::isPointerButtonDown(PointerEventButton pointerButton) const
 	{
 	{
-		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn;
+		return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn ||
+			mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
 	}
 	}
 
 
 	bool Input::isPointerDoubleClicked() const
 	bool Input::isPointerDoubleClicked() const

+ 102 - 20
BansheeCore/Source/BsRenderWindow.cpp

@@ -40,6 +40,16 @@ namespace BansheeEngine
 	void RenderWindowCore::setHidden(bool hidden)
 	void RenderWindowCore::setHidden(bool hidden)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
+
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+
+		props.mHidden = hidden;
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mHidden = hidden;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void RenderWindowCore::setActive(bool state)
 	void RenderWindowCore::setActive(bool state)
@@ -49,19 +59,28 @@ namespace BansheeEngine
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 
 
 		props.mActive = state;
 		props.mActive = state;
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
-	}
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mActive = state;
+		}
 
 
-	void RenderWindowCore::syncToCore(const CoreSyncData& data)
-	{
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-		props = data.getData<RenderWindowProperties>();
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void RenderWindowCore::_windowMovedOrResized()
 	void RenderWindowCore::_windowMovedOrResized()
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mTop = props.mTop;
+			getSyncedProperties().mLeft = props.mLeft;
+			getSyncedProperties().mWidth = props.mWidth;
+			getSyncedProperties().mHeight = props.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -71,7 +90,12 @@ namespace BansheeEngine
 
 
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		properties.mHasFocus = true;
 		properties.mHasFocus = true;
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mHasFocus = true;
+		}
 
 
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyFocusReceived(this);
 		RenderWindowManager::instance().notifyFocusReceived(this);
 	}
 	}
 
 
@@ -81,7 +105,12 @@ namespace BansheeEngine
 
 
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& properties = const_cast<RenderWindowProperties&>(getProperties());
 		properties.mHasFocus = false;
 		properties.mHasFocus = false;
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mHasFocus = false;
+		}
 
 
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyFocusLost(this);
 		RenderWindowManager::instance().notifyFocusLost(this);
 	}
 	}
 
 
@@ -92,7 +121,12 @@ namespace BansheeEngine
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 
 
 		props.mIsMaximized = true;
 		props.mIsMaximized = true;
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mIsMaximized = true;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void RenderWindowCore::_notifyMinimized()
 	void RenderWindowCore::_notifyMinimized()
@@ -102,7 +136,12 @@ namespace BansheeEngine
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 
 
 		props.mIsMaximized = false;
 		props.mIsMaximized = false;
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mIsMaximized = false;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void RenderWindowCore::_notifyRestored()
 	void RenderWindowCore::_notifyRestored()
@@ -112,7 +151,12 @@ namespace BansheeEngine
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
 
 
 		props.mIsMaximized = false;
 		props.mIsMaximized = false;
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		{
+			ScopedSpinLock lock(mLock);
+			getSyncedProperties().mIsMaximized = false;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	const RenderWindowProperties& RenderWindowCore::getProperties() const
 	const RenderWindowProperties& RenderWindowCore::getProperties() const
@@ -143,6 +187,14 @@ namespace BansheeEngine
 
 
 		getMutableProperties().mWidth = width;
 		getMutableProperties().mWidth = width;
 		getMutableProperties().mHeight = height;
 		getMutableProperties().mHeight = height;
+
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mWidth = width;
+			getCore()->getSyncedProperties().mHeight = height;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		onResized();
 		onResized();
 
 
 		accessor.queueCommand(std::bind(resizeFunc, getCore(), width, height));
 		accessor.queueCommand(std::bind(resizeFunc, getCore(), width, height));
@@ -158,6 +210,14 @@ namespace BansheeEngine
 
 
 		getMutableProperties().mLeft = left;
 		getMutableProperties().mLeft = left;
 		getMutableProperties().mTop = top;
 		getMutableProperties().mTop = top;
+
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mLeft = left;
+			getCore()->getSyncedProperties().mTop = top;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(moveFunc, getCore(), left, top));
 		accessor.queueCommand(std::bind(moveFunc, getCore(), left, top));
 	}
 	}
 
 
@@ -170,6 +230,12 @@ namespace BansheeEngine
 		};
 		};
 
 
 		getMutableProperties().mHidden = true;
 		getMutableProperties().mHidden = true;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mHidden = true;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(hideFunc, getCore()));
 		accessor.queueCommand(std::bind(hideFunc, getCore()));
 	}
 	}
 
 
@@ -182,6 +248,12 @@ namespace BansheeEngine
 		};
 		};
 
 
 		getMutableProperties().mHidden = false;
 		getMutableProperties().mHidden = false;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mHidden = false;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(showFunc, getCore()));
 		accessor.queueCommand(std::bind(showFunc, getCore()));
 	}
 	}
 
 
@@ -193,6 +265,13 @@ namespace BansheeEngine
 			renderWindow->minimize();
 			renderWindow->minimize();
 		};
 		};
 
 
+		getMutableProperties().mIsMaximized = false;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mIsMaximized = false;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(minimizeFunc, getCore()));
 		accessor.queueCommand(std::bind(minimizeFunc, getCore()));
 	}
 	}
 
 
@@ -204,6 +283,13 @@ namespace BansheeEngine
 			renderWindow->maximize();
 			renderWindow->maximize();
 		};
 		};
 
 
+		getMutableProperties().mIsMaximized = true;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mIsMaximized = true;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(maximizeFunc, getCore()));
 		accessor.queueCommand(std::bind(maximizeFunc, getCore()));
 	}
 	}
 
 
@@ -215,6 +301,13 @@ namespace BansheeEngine
 			renderWindow->restore();
 			renderWindow->restore();
 		};
 		};
 
 
+		getMutableProperties().mIsMaximized = false;
+		{
+			ScopedSpinLock lock(getCore()->mLock);
+			getCore()->getSyncedProperties().mIsMaximized = false;
+		}
+
+		RenderWindowCoreManager::instance().notifySyncDataDirty(getCore().get());
 		accessor.queueCommand(std::bind(restoreFunc, getCore()));
 		accessor.queueCommand(std::bind(restoreFunc, getCore()));
 	}
 	}
 
 
@@ -273,17 +366,6 @@ namespace BansheeEngine
 		return const_cast<RenderWindowProperties&>(getProperties());
 		return const_cast<RenderWindowProperties&>(getProperties());
 	}
 	}
 
 
-	CoreSyncData RenderWindow::syncToCore(FrameAlloc* allocator)
-	{
-		UINT32 size = sizeof(RenderWindowProperties);
-		UINT8* buffer = allocator->alloc(size);
-
-		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
-
-		memcpy(buffer, &props, size);
-		return CoreSyncData(buffer, size);
-	}
-
 	const RenderWindowProperties& RenderWindow::getProperties() const
 	const RenderWindowProperties& RenderWindow::getProperties() const
 	{
 	{
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());

+ 23 - 56
BansheeCore/Source/BsRenderWindowManager.cpp

@@ -13,15 +13,7 @@ namespace BansheeEngine
 
 
 	RenderWindowManager::~RenderWindowManager()
 	RenderWindowManager::~RenderWindowManager()
 	{
 	{
-		for (auto& dirtyPropertyEntry : mDirtyProperties)
-		{
-			DirtyPropertyData& dirtyPropertyData = dirtyPropertyEntry.second;
-
-			if (dirtyPropertyEntry.second.data != nullptr)
-				bs_delete(dirtyPropertyEntry.second.data);
-		}
 
 
-		mDirtyProperties.clear();
 	}
 	}
 
 
 	RenderWindowPtr RenderWindowManager::create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
 	RenderWindowPtr RenderWindowManager::create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
@@ -58,17 +50,10 @@ namespace BansheeEngine
 			if(iterFind2 != mMovedOrResizedWindows.end())
 			if(iterFind2 != mMovedOrResizedWindows.end())
 				mMovedOrResizedWindows.erase(iterFind2);
 				mMovedOrResizedWindows.erase(iterFind2);
 
 
-			auto iterFind3 = mDirtyProperties.find(window);
-			if (iterFind3 != mDirtyProperties.end())
-			{
-				if (iterFind3->second.data != nullptr)
-					bs_delete(iterFind3->second.data);
-
-				mDirtyProperties.erase(iterFind3);
-			}
-
 			mCoreToNonCoreMap.erase(window->getCore().get());
 			mCoreToNonCoreMap.erase(window->getCore().get());
 		}
 		}
+
+		mDirtyProperties.erase(window);
 	}
 	}
 
 
 	void RenderWindowManager::notifyFocusReceived(RenderWindowCore* coreWindow)
 	void RenderWindowManager::notifyFocusReceived(RenderWindowCore* coreWindow)
@@ -77,8 +62,6 @@ namespace BansheeEngine
 
 
 		BS_LOCK_MUTEX(mWindowMutex);
 		BS_LOCK_MUTEX(mWindowMutex);
 		mNewWindowInFocus = window;
 		mNewWindowInFocus = window;
-
-		setDirtyProperties(coreWindow);
 	}
 	}
 
 
 	void RenderWindowManager::notifyFocusLost(RenderWindowCore* coreWindow)
 	void RenderWindowManager::notifyFocusLost(RenderWindowCore* coreWindow)
@@ -87,8 +70,6 @@ namespace BansheeEngine
 
 
 		BS_LOCK_MUTEX(mWindowMutex);
 		BS_LOCK_MUTEX(mWindowMutex);
 		mNewWindowInFocus = nullptr;
 		mNewWindowInFocus = nullptr;
-
-		setDirtyProperties(coreWindow);
 	}
 	}
 
 
 	void RenderWindowManager::notifyMovedOrResized(RenderWindowCore* coreWindow)
 	void RenderWindowManager::notifyMovedOrResized(RenderWindowCore* coreWindow)
@@ -131,35 +112,14 @@ namespace BansheeEngine
 		moveResizeData->y = props.getTop();
 		moveResizeData->y = props.getTop();
 		moveResizeData->width = props.getWidth();
 		moveResizeData->width = props.getWidth();
 		moveResizeData->height = props.getHeight();
 		moveResizeData->height = props.getHeight();
-
-		setDirtyProperties(coreWindow);
 	}
 	}
 
 
-	void RenderWindowManager::notifyPropertiesDirty(RenderWindowCore* coreWindow)
+	void RenderWindowManager::notifySyncDataDirty(RenderWindowCore* coreWindow)
 	{
 	{
-		RenderWindow* window = getNonCore(coreWindow);
-
 		BS_LOCK_MUTEX(mWindowMutex);
 		BS_LOCK_MUTEX(mWindowMutex);
-		setDirtyProperties(coreWindow);
-	}
 
 
-	void RenderWindowManager::setDirtyProperties(RenderWindowCore* coreWindow)
-	{
 		RenderWindow* window = getNonCore(coreWindow);
 		RenderWindow* window = getNonCore(coreWindow);
-
-		auto iterFind = mDirtyProperties.find(window);
-		if (iterFind != mDirtyProperties.end())
-		{
-			if (iterFind->second.data != nullptr)
-				bs_delete(iterFind->second.data);
-		}
-
-		mDirtyProperties[window] = DirtyPropertyData();
-		DirtyPropertyData& dirtyPropertyData = mDirtyProperties[window];
-		dirtyPropertyData.size = coreWindow->getSyncData(nullptr);
-		dirtyPropertyData.data = (UINT8*)bs_alloc(dirtyPropertyData.size);
-
-		coreWindow->getSyncData(dirtyPropertyData.data);
+		mDirtyProperties.insert(window);
 	}
 	}
 
 
 	void RenderWindowManager::windowMouseLeft(RenderWindowCore* coreWindow)
 	void RenderWindowManager::windowMouseLeft(RenderWindowCore* coreWindow)
@@ -202,20 +162,12 @@ namespace BansheeEngine
 
 
 			mouseLeftWindows = mMouseLeftWindows;
 			mouseLeftWindows = mMouseLeftWindows;
 			mMouseLeftWindows.clear();
 			mMouseLeftWindows.clear();
+		}
 
 
-			for (auto& dirtyPropertyEntry : mDirtyProperties)
-			{
-				RenderWindow* window = dirtyPropertyEntry.first;
-				DirtyPropertyData& dirtyPropertyData = dirtyPropertyEntry.second;
-
-				window->setSyncData(dirtyPropertyData.data, dirtyPropertyData.size);
-
-				if (dirtyPropertyEntry.second.data != nullptr)
-					bs_delete(dirtyPropertyEntry.second.data);
-			}
+		for (auto& dirtyPropertyWindow : mDirtyProperties)
+			dirtyPropertyWindow->syncProperties();
 
 
-			mDirtyProperties.clear();
-		}
+		mDirtyProperties.clear();
 
 
 		if(mWindowInFocus != newWinInFocus)
 		if(mWindowInFocus != newWinInFocus)
 		{
 		{
@@ -265,6 +217,14 @@ namespace BansheeEngine
 		return renderWindow;
 		return renderWindow;
 	}
 	}
 
 
+	void RenderWindowCoreManager::_update()
+	{
+		for (auto& dirtyPropertyWindow : mDirtyProperties)
+			dirtyPropertyWindow->syncProperties();
+
+		mDirtyProperties.clear();
+	}
+
 	void RenderWindowCoreManager::windowCreated(RenderWindowCore* window)
 	void RenderWindowCoreManager::windowCreated(RenderWindowCore* window)
 	{
 	{
 		BS_LOCK_MUTEX(mWindowMutex);
 		BS_LOCK_MUTEX(mWindowMutex);
@@ -284,6 +244,8 @@ namespace BansheeEngine
 
 
 			mCreatedWindows.erase(iterFind);
 			mCreatedWindows.erase(iterFind);
 		}
 		}
+
+		mDirtyProperties.erase(window);
 	}
 	}
 
 
 	Vector<RenderWindowCore*> RenderWindowCoreManager::getRenderWindows() const
 	Vector<RenderWindowCore*> RenderWindowCoreManager::getRenderWindows() const
@@ -292,4 +254,9 @@ namespace BansheeEngine
 
 
 		return mCreatedWindows;
 		return mCreatedWindows;
 	}
 	}
+
+	void RenderWindowCoreManager::notifySyncDataDirty(RenderWindowCore* window)
+	{
+		mDirtyProperties.insert(window);
+	}
 }
 }

+ 10 - 4
BansheeD3D11RenderSystem/Include/BsD3D11RenderWindow.h

@@ -156,9 +156,14 @@ namespace BansheeEngine
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
 		/**
 		/**
-		 * @copydoc	RenderWindowCore::getSyncData
+		 * @copydoc	RenderWindowCore::getSyncedProperties
 		 */
 		 */
-		UINT32 getSyncData(UINT8* buffer);
+		RenderWindowProperties& getSyncedProperties() override { return mSyncedProperties; }
+
+		/**
+		 * @copydoc	RenderWindowCore::syncProperties
+		 */
+		void syncProperties() override;
 
 
 	protected:
 	protected:
 		D3D11Device& mDevice;
 		D3D11Device& mDevice;
@@ -181,6 +186,7 @@ namespace BansheeEngine
 		HWND mHWnd;
 		HWND mHWnd;
 
 
 		D3D11RenderWindowProperties mProperties;
 		D3D11RenderWindowProperties mProperties;
+		D3D11RenderWindowProperties mSyncedProperties;
 	};
 	};
 
 
 	/**
 	/**
@@ -225,9 +231,9 @@ namespace BansheeEngine
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
 		/**
 		/**
-		 * @copydoc	RenderWindow::setSyncData
+		 * @copydoc	RenderWindow::syncProperties
 		 */
 		 */
-		void setSyncData(UINT8* buffer, UINT32 size);
+		void syncProperties() override;
 
 
 		/**
 		/**
 		 * @brief	Retrieves internal window handle.
 		 * @brief	Retrieves internal window handle.

+ 66 - 21
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -21,8 +21,8 @@ namespace BansheeEngine
 	{ }
 	{ }
 
 
 	D3D11RenderWindowCore::D3D11RenderWindowCore(const RENDER_WINDOW_DESC& desc, D3D11Device& device, IDXGIFactory* DXGIFactory)
 	D3D11RenderWindowCore::D3D11RenderWindowCore(const RENDER_WINDOW_DESC& desc, D3D11Device& device, IDXGIFactory* DXGIFactory)
-		: RenderWindowCore(desc), mProperties(desc), mDevice(device), mDXGIFactory(DXGIFactory), mIsExternal(false), mSizing(false),
-		 mRenderTargetView(nullptr), mBackBuffer(nullptr), mSwapChain(nullptr), mDepthStencilView(nullptr), mIsChild(false), 
+		: RenderWindowCore(desc), mProperties(desc), mSyncedProperties(desc), mDevice(device), mDXGIFactory(DXGIFactory), mIsExternal(false), 
+		mSizing(false), mRenderTargetView(nullptr), mBackBuffer(nullptr), mSwapChain(nullptr), mDepthStencilView(nullptr), mIsChild(false), 
 		 mRefreshRateNumerator(0), mRefreshRateDenominator(0), mHWnd(0)
 		 mRefreshRateNumerator(0), mRefreshRateDenominator(0), mHWnd(0)
 	{ }
 	{ }
 
 
@@ -268,6 +268,13 @@ namespace BansheeEngine
 		createSizeDependedD3DResources();
 		createSizeDependedD3DResources();
 		mDXGIFactory->MakeWindowAssociation(mHWnd, NULL);
 		mDXGIFactory->MakeWindowAssociation(mHWnd, NULL);
 		setHidden(props.isHidden());
 		setHidden(props.isHidden());
+
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties = props;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void D3D11RenderWindowCore::swapBuffers()
 	void D3D11RenderWindowCore::swapBuffers()
@@ -294,7 +301,15 @@ namespace BansheeEngine
 			props.mTop = top;
 			props.mTop = top;
 			props.mLeft = left;
 			props.mLeft = left;
 
 
-			SetWindowPos(mHWnd, 0, top, left, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);		
+			SetWindowPos(mHWnd, 0, top, left, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);	
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mTop = props.mTop;
+				mSyncedProperties.mLeft = props.mLeft;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -315,6 +330,14 @@ namespace BansheeEngine
 			height = rc.bottom - rc.top;
 			height = rc.bottom - rc.top;
 
 
 			SetWindowPos(mHWnd, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
 			SetWindowPos(mHWnd, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mWidth = props.mWidth;
+				mSyncedProperties.mHeight = props.mHeight;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -356,7 +379,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 		}
 
 
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		RenderWindowCore::setHidden(hidden);
 	}
 	}
 
 
 	void D3D11RenderWindowCore::minimize()
 	void D3D11RenderWindowCore::minimize()
@@ -421,6 +444,15 @@ namespace BansheeEngine
 		mSwapChain->ResizeTarget(&nearestMode);
 		mSwapChain->ResizeTarget(&nearestMode);
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput()); 
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput()); 
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = mProperties.mTop;
+			mSyncedProperties.mLeft = mProperties.mLeft;
+			mSyncedProperties.mWidth = mProperties.mWidth;
+			mSyncedProperties.mHeight = mProperties.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -454,6 +486,15 @@ namespace BansheeEngine
 		mSwapChain->ResizeTarget(&videoMode.getDXGIModeDesc());
 		mSwapChain->ResizeTarget(&videoMode.getDXGIModeDesc());
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput());
 		mSwapChain->SetFullscreenState(true, outputInfo.getDXGIOutput());
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = mProperties.mTop;
+			mSyncedProperties.mLeft = mProperties.mLeft;
+			mSyncedProperties.mWidth = mProperties.mWidth;
+			mSyncedProperties.mHeight = mProperties.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -483,6 +524,15 @@ namespace BansheeEngine
 		mSwapChain->SetFullscreenState(false, nullptr);
 		mSwapChain->SetFullscreenState(false, nullptr);
 		mSwapChain->ResizeTarget(&modeDesc);
 		mSwapChain->ResizeTarget(&modeDesc);
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = mProperties.mTop;
+			mSyncedProperties.mLeft = mProperties.mLeft;
+			mSyncedProperties.mWidth = mProperties.mWidth;
+			mSyncedProperties.mHeight = mProperties.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -743,16 +793,6 @@ namespace BansheeEngine
 		mDevice.getImmediateContext()->OMSetRenderTargets(0, 0, 0);
 		mDevice.getImmediateContext()->OMSetRenderTargets(0, 0, 0);
 	}
 	}
 
 
-	UINT32 D3D11RenderWindowCore::getSyncData(UINT8* buffer)
-	{
-		UINT32 size = sizeof(mProperties);
-
-		if (buffer != nullptr)
-			memcpy(buffer, &mProperties, size);
-
-		return size;
-	}
-
 	IDXGIDevice* D3D11RenderWindowCore::queryDxgiDevice()
 	IDXGIDevice* D3D11RenderWindowCore::queryDxgiDevice()
 	{
 	{
 		if (mDevice.getD3D11Device() == nullptr)
 		if (mDevice.getD3D11Device() == nullptr)
@@ -769,6 +809,12 @@ namespace BansheeEngine
 		return pDXGIDevice;
 		return pDXGIDevice;
 	}
 	}
 
 
+	void D3D11RenderWindowCore::syncProperties()
+	{
+		ScopedSpinLock lock(mLock);
+		mProperties = mSyncedProperties;
+	}
+
 	D3D11RenderWindow::D3D11RenderWindow(const RENDER_WINDOW_DESC& desc, D3D11Device& device, IDXGIFactory* DXGIFactory)
 	D3D11RenderWindow::D3D11RenderWindow(const RENDER_WINDOW_DESC& desc, D3D11Device& device, IDXGIFactory* DXGIFactory)
 		:RenderWindow(desc), mProperties(desc), mDevice(device), mDXGIFactory(DXGIFactory)
 		:RenderWindow(desc), mProperties(desc), mDevice(device), mDXGIFactory(DXGIFactory)
 	{
 	{
@@ -805,13 +851,6 @@ namespace BansheeEngine
 		return Vector2I(pos.x, pos.y);
 		return Vector2I(pos.x, pos.y);
 	}
 	}
 
 
-	void D3D11RenderWindow::setSyncData(UINT8* buffer, UINT32 size)
-	{
-		assert(size == sizeof(mProperties));
-
-		memcpy(&mProperties, buffer, size);
-	}
-
 	SPtr<D3D11RenderWindowCore> D3D11RenderWindow::getCore() const
 	SPtr<D3D11RenderWindowCore> D3D11RenderWindow::getCore() const
 	{
 	{
 		return std::static_pointer_cast<D3D11RenderWindowCore>(mCoreSpecific);
 		return std::static_pointer_cast<D3D11RenderWindowCore>(mCoreSpecific);
@@ -823,4 +862,10 @@ namespace BansheeEngine
 		// could be returned here if requested too soon after initialization.
 		// could be returned here if requested too soon after initialization.
 		return getCore()->_getWindowHandle();
 		return getCore()->_getWindowHandle();
 	}
 	}
+
+	void D3D11RenderWindow::syncProperties()
+	{
+		ScopedSpinLock lock(getCore()->mLock);
+		mProperties = getCore()->mSyncedProperties;
+	}
 }
 }

+ 10 - 4
BansheeD3D9RenderSystem/Include/BsD3D9RenderWindow.h

@@ -163,9 +163,14 @@ namespace BansheeEngine
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
 		/**
 		/**
-		 * @copydoc	RenderWindowCore::getSyncData
+		 * @copydoc	RenderWindowCore::getSyncedProperties
 		 */
 		 */
-		UINT32 getSyncData(UINT8* buffer);
+		RenderWindowProperties& getSyncedProperties() override { return mSyncedProperties; }
+
+		/**
+		 * @copydoc	RenderWindowCore::syncProperties
+		 */
+		void syncProperties() override;
 
 
 	protected:
 	protected:
 		HINSTANCE mInstance;
 		HINSTANCE mInstance;
@@ -184,6 +189,7 @@ namespace BansheeEngine
 		HWND mHWnd;
 		HWND mHWnd;
 
 
 		D3D9RenderWindowProperties mProperties;
 		D3D9RenderWindowProperties mProperties;
+		D3D9RenderWindowProperties mSyncedProperties;
 	};
 	};
 
 
 	/**
 	/**
@@ -228,9 +234,9 @@ namespace BansheeEngine
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
 		/**
 		/**
-		 * @copydoc	RenderWindow::setSyncData
+		 * @copydoc	RenderWindow::syncProperties
 		 */
 		 */
-		void setSyncData(UINT8* buffer, UINT32 size);
+		void syncProperties() override;
 
 
 		/**
 		/**
 		 * @brief	Retrieves internal window handle.
 		 * @brief	Retrieves internal window handle.

+ 55 - 19
BansheeD3D9RenderSystem/Source/BsD3D9RenderWindow.cpp

@@ -20,7 +20,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	D3D9RenderWindowCore::D3D9RenderWindowCore(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
 	D3D9RenderWindowCore::D3D9RenderWindowCore(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
-		: RenderWindowCore(desc), mInstance(instance), mProperties(desc), mIsDepthBuffered(true), mIsChild(false), mHWnd(0),
+		: RenderWindowCore(desc), mInstance(instance), mProperties(desc), mSyncedProperties(desc), mIsDepthBuffered(true), mIsChild(false), mHWnd(0),
 		mStyle(0), mWindowedStyle(0), mWindowedStyleEx(0), mDevice(nullptr), mIsExternal(false), mDisplayFrequency(0), mDeviceValid(false)
 		mStyle(0), mWindowedStyle(0), mWindowedStyleEx(0), mDevice(nullptr), mIsExternal(false), mDisplayFrequency(0), mDeviceValid(false)
 	{ }
 	{ }
 
 
@@ -237,6 +237,13 @@ namespace BansheeEngine
 
 
 		D3D9RenderAPI* rs = static_cast<D3D9RenderAPI*>(RenderAPICore::instancePtr());
 		D3D9RenderAPI* rs = static_cast<D3D9RenderAPI*>(RenderAPICore::instancePtr());
 		rs->registerWindow(*this);
 		rs->registerWindow(*this);
+
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties = props;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void D3D9RenderWindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
 	void D3D9RenderWindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
@@ -277,6 +284,15 @@ namespace BansheeEngine
 		mDevice->invalidate(this);
 		mDevice->invalidate(this);
 		mDevice->acquire();
 		mDevice->acquire();
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = props.mTop;
+			mSyncedProperties.mLeft = props.mLeft;
+			mSyncedProperties.mWidth = props.mWidth;
+			mSyncedProperties.mHeight = props.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -325,6 +341,15 @@ namespace BansheeEngine
 		mDevice->invalidate(this);
 		mDevice->invalidate(this);
 		mDevice->acquire();
 		mDevice->acquire();
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = props.mTop;
+			mSyncedProperties.mLeft = props.mLeft;
+			mSyncedProperties.mWidth = props.mWidth;
+			mSyncedProperties.mHeight = props.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -343,7 +368,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 		}
 
 
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		RenderWindowCore::setHidden(hidden);
 	}
 	}
 
 
 	void D3D9RenderWindowCore::minimize()
 	void D3D9RenderWindowCore::minimize()
@@ -382,6 +407,14 @@ namespace BansheeEngine
 			props.mTop = top;
 			props.mTop = top;
 
 
 			SetWindowPos(mHWnd, 0, top, left, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
 			SetWindowPos(mHWnd, 0, top, left, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mLeft = props.mLeft;
+				mSyncedProperties.mTop = props.mTop;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -401,6 +434,14 @@ namespace BansheeEngine
 
 
 			SetWindowPos(mHWnd, 0, 0, 0, winWidth, winHeight,
 			SetWindowPos(mHWnd, 0, 0, 0, winWidth, winHeight,
 				SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
 				SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mWidth = props.mWidth;
+				mSyncedProperties.mHeight = props.mHeight;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -685,22 +726,18 @@ namespace BansheeEngine
 		props.mHeight = rc.bottom - rc.top;
 		props.mHeight = rc.bottom - rc.top;
 	}
 	}
 
 
-	UINT32 D3D9RenderWindowCore::getSyncData(UINT8* buffer)
-	{
-		UINT32 size = sizeof(mProperties);
-
-		if (buffer != nullptr)
-			memcpy(buffer, &mProperties, size);
-
-		return size;
-	}
-
 	bool D3D9RenderWindowCore::_validateDevice()
 	bool D3D9RenderWindowCore::_validateDevice()
 	{
 	{
 		mDeviceValid = mDevice->validate(this);
 		mDeviceValid = mDevice->validate(this);
 		return mDeviceValid;
 		return mDeviceValid;
 	}
 	}
 
 
+	void D3D9RenderWindowCore::syncProperties()
+	{
+		ScopedSpinLock lock(mLock);
+		mProperties = mSyncedProperties;
+	}
+
 	D3D9RenderWindow::D3D9RenderWindow(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
 	D3D9RenderWindow::D3D9RenderWindow(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
 		:RenderWindow(desc), mInstance(instance), mProperties(desc)
 		:RenderWindow(desc), mInstance(instance), mProperties(desc)
 	{
 	{
@@ -737,13 +774,6 @@ namespace BansheeEngine
 		return Vector2I(pos.x, pos.y);
 		return Vector2I(pos.x, pos.y);
 	}
 	}
 
 
-	void D3D9RenderWindow::setSyncData(UINT8* buffer, UINT32 size)
-	{
-		assert(size == sizeof(mProperties));
-
-		memcpy(&mProperties, buffer, size);
-	}
-
 	HWND D3D9RenderWindow::getHWnd() const
 	HWND D3D9RenderWindow::getHWnd() const
 	{
 	{
 		// HACK: I'm accessing core method from sim thread, which means an invalid handle
 		// HACK: I'm accessing core method from sim thread, which means an invalid handle
@@ -755,4 +785,10 @@ namespace BansheeEngine
 	{
 	{
 		return std::static_pointer_cast<D3D9RenderWindowCore>(mCoreSpecific);
 		return std::static_pointer_cast<D3D9RenderWindowCore>(mCoreSpecific);
 	}
 	}
+
+	void D3D9RenderWindow::syncProperties()
+	{
+		ScopedSpinLock lock(getCore()->mLock);
+		mProperties = getCore()->mSyncedProperties;
+	}
 }
 }

+ 2 - 2
BansheeD3D9RenderSystem/Source/BsD3D9Texture.cpp

@@ -62,7 +62,7 @@ namespace BansheeEngine
 
 
 	PixelData D3D9TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	PixelData D3D9TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
 	{
-		if (mProperties.getMultisampleCount() > 0)
+		if (mProperties.getMultisampleCount() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
 
 
 		if(mLockedBuffer != nullptr)
 		if(mLockedBuffer != nullptr)
@@ -185,7 +185,7 @@ namespace BansheeEngine
 
 
 	void D3D9TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
 	void D3D9TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
 	{
 	{
-		if (mProperties.getMultisampleCount() > 0)
+		if (mProperties.getMultisampleCount() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
 
 
 		if (mProperties.getUsage() == TU_DYNAMIC || mProperties.getUsage() == TU_STATIC)
 		if (mProperties.getUsage() == TU_DYNAMIC || mProperties.getUsage() == TU_STATIC)

+ 3 - 1
BansheeEditor/Source/BsSceneViewHandler.cpp

@@ -42,7 +42,6 @@ namespace BansheeEngine
 
 
 	void SceneViewHandler::update()
 	void SceneViewHandler::update()
 	{
 	{
-		mSelectionRenderer->update(mCamera);
 		GizmoManager::instance().update(mCamera);
 		GizmoManager::instance().update(mCamera);
 		mSceneGrid->update();
 		mSceneGrid->update();
 	}
 	}
@@ -57,6 +56,9 @@ namespace BansheeEngine
 			mMouseDeltaCompensate = wrapCursorToWindow();
 			mMouseDeltaCompensate = wrapCursorToWindow();
 
 
 		HandleManager::instance().update(mCamera, position, realDelta);
 		HandleManager::instance().update(mCamera, position, realDelta);
+
+		// Update selection here since this is triggered after user potentially selects a new object
+		mSelectionRenderer->update(mCamera);
 	}
 	}
 
 
 	void SceneViewHandler::trySelectHandle(const Vector2I& position)
 	void SceneViewHandler::trySelectHandle(const Vector2I& position)

+ 1 - 1
BansheeEditorExec/BsEditorExec.cpp

@@ -65,7 +65,7 @@ int CALLBACK WinMain(
 	InitializeDebugConsole();
 	InitializeDebugConsole();
 #endif
 #endif
 
 
-	EditorApplication::startUp(RenderSystemPlugin::DX11);
+	EditorApplication::startUp(RenderSystemPlugin::OpenGL);
 	EditorApplication::instance().runMainLoop();
 	EditorApplication::instance().runMainLoop();
 	EditorApplication::shutDown();
 	EditorApplication::shutDown();
 
 

+ 15 - 7
BansheeGLRenderSystem/Include/BsWin32Window.h

@@ -120,11 +120,6 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void initialize();
 		virtual void initialize();
 
 
-		/**
-		 * @copydoc	RenderWindowCore::getSyncData
-		 */
-		UINT32 getSyncData(UINT8* buffer);
-		
 		/**
 		/**
 		 * @brief	Calculates window size based on provided client area size and currently set window style. 
 		 * @brief	Calculates window size based on provided client area size and currently set window style. 
 		 */
 		 */
@@ -135,7 +130,19 @@ namespace BansheeEngine
 		 */
 		 */
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
+		/**
+		 * @copydoc	RenderWindowCore::getSyncedProperties
+		 */
+		RenderWindowProperties& getSyncedProperties() override { return mSyncedProperties; }
+
+		/**
+		 * @copydoc	RenderWindowCore::syncProperties
+		 */
+		void syncProperties() override;
+
 	protected:
 	protected:
+		friend class Win32Window;
+
 		Win32GLSupport &mGLSupport;
 		Win32GLSupport &mGLSupport;
 		HDC	mHDC;
 		HDC	mHDC;
 		DWORD mWindowedStyle;
 		DWORD mWindowedStyle;
@@ -148,6 +155,7 @@ namespace BansheeEngine
 		HWND mHWnd;
 		HWND mHWnd;
 		SPtr<Win32Context> mContext;
 		SPtr<Win32Context> mContext;
 		Win32RenderWindowProperties mProperties;
 		Win32RenderWindowProperties mProperties;
+		Win32RenderWindowProperties mSyncedProperties;
     };
     };
 
 
 	/**
 	/**
@@ -193,9 +201,9 @@ namespace BansheeEngine
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 		const RenderTargetProperties& getPropertiesInternal() const { return mProperties; }
 
 
 		/**
 		/**
-		 * @copydoc	RenderWindow::setSyncData
+		 * @copydoc	RenderWindow::syncProperties
 		 */
 		 */
-		void setSyncData(UINT8* buffer, UINT32 size);
+		void syncProperties() override;
 
 
 		/**
 		/**
 		 * @brief	Retrieves internal window handle.
 		 * @brief	Retrieves internal window handle.

+ 49 - 15
BansheeGLRenderSystem/Source/BsWin32Window.cpp

@@ -25,8 +25,8 @@ namespace BansheeEngine
 	{ }
 	{ }
 
 
 	Win32WindowCore::Win32WindowCore(const RENDER_WINDOW_DESC& desc, Win32GLSupport& glsupport)
 	Win32WindowCore::Win32WindowCore(const RENDER_WINDOW_DESC& desc, Win32GLSupport& glsupport)
-		: RenderWindowCore(desc), mProperties(desc), mGLSupport(glsupport), mContext(0), mWindowedStyle(0), mWindowedStyleEx(0), mIsExternal(false),
-		mIsExternalGLControl(false), mDisplayFrequency(0), mDeviceName(nullptr), mHWnd(0)
+		: RenderWindowCore(desc), mProperties(desc), mSyncedProperties(desc), mGLSupport(glsupport), mContext(0), 
+		mWindowedStyle(0), mWindowedStyleEx(0), mIsExternal(false), mIsExternalGLControl(false), mDisplayFrequency(0), mDeviceName(nullptr), mHWnd(0)
 	{ }
 	{ }
 
 
 	Win32WindowCore::~Win32WindowCore()
 	Win32WindowCore::~Win32WindowCore()
@@ -348,6 +348,13 @@ namespace BansheeEngine
 
 
 		props.mActive = true;
 		props.mActive = true;
 		mContext = mGLSupport.createContext(mHDC, glrc);
 		mContext = mGLSupport.createContext(mHDC, glrc);
+
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties = props;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 	}
 	}
 
 
 	void Win32WindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
 	void Win32WindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
@@ -401,6 +408,15 @@ namespace BansheeEngine
 
 
 		SetWindowPos(mHWnd, HWND_TOP, props.mLeft, props.mTop, width, height, SWP_NOACTIVATE);
 		SetWindowPos(mHWnd, HWND_TOP, props.mLeft, props.mTop, width, height, SWP_NOACTIVATE);
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mTop = props.mTop;
+			mSyncedProperties.mLeft = props.mLeft;
+			mSyncedProperties.mWidth = props.mWidth;
+			mSyncedProperties.mHeight = props.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 		RenderWindowManager::instance().notifyMovedOrResized(this);
 	}
 	}
 
 
@@ -449,6 +465,13 @@ namespace BansheeEngine
 		SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
 		SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
 			SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
 			SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
 
 
+		{
+			ScopedSpinLock lock(mLock);
+			mSyncedProperties.mWidth = props.mWidth;
+			mSyncedProperties.mHeight = props.mHeight;
+		}
+
+		RenderWindowManager::instance().notifySyncDataDirty(this);
 		_windowMovedOrResized();
 		_windowMovedOrResized();
 	}
 	}
 
 
@@ -464,6 +487,14 @@ namespace BansheeEngine
 
 
 			SetWindowPos(mHWnd, 0, left, top, 0, 0,
 			SetWindowPos(mHWnd, 0, left, top, 0, 0,
 				SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
 				SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mTop = props.mTop;
+				mSyncedProperties.mLeft = props.mLeft;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -483,6 +514,14 @@ namespace BansheeEngine
 			height = rc.bottom - rc.top;
 			height = rc.bottom - rc.top;
 			SetWindowPos(mHWnd, 0, 0, 0, width, height,
 			SetWindowPos(mHWnd, 0, 0, 0, width, height,
 				SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
 				SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+			{
+				ScopedSpinLock lock(mLock);
+				mSyncedProperties.mWidth = props.mWidth;
+				mSyncedProperties.mHeight = props.mHeight;
+			}
+
+			RenderWindowManager::instance().notifySyncDataDirty(this);
 		}
 		}
 	}
 	}
 
 
@@ -639,7 +678,7 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		RenderWindowCore::setActive(state);
 	}
 	}
 
 
 	void Win32WindowCore::setHidden(bool hidden)
 	void Win32WindowCore::setHidden(bool hidden)
@@ -656,7 +695,7 @@ namespace BansheeEngine
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 				ShowWindow(mHWnd, SW_SHOWNORMAL);
 		}
 		}
 
 
-		RenderWindowManager::instance().notifyPropertiesDirty(this);
+		RenderWindowCore::setHidden(hidden);
 	}
 	}
 
 
 	void Win32WindowCore::_windowMovedOrResized()
 	void Win32WindowCore::_windowMovedOrResized()
@@ -708,14 +747,10 @@ namespace BansheeEngine
 			*winHeight = maxH;
 			*winHeight = maxH;
 	}
 	}
 
 
-	UINT32 Win32WindowCore::getSyncData(UINT8* buffer)
+	void Win32WindowCore::syncProperties()
 	{
 	{
-		UINT32 size = sizeof(mProperties);
-
-		if (buffer != nullptr)
-			memcpy(buffer, &mProperties, size);
-
-		return size;
+		ScopedSpinLock lock(mLock);
+		mProperties = mSyncedProperties;
 	}
 	}
 
 
 	Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport)
 	Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport)
@@ -759,11 +794,10 @@ namespace BansheeEngine
 		return std::static_pointer_cast<Win32WindowCore>(mCoreSpecific);
 		return std::static_pointer_cast<Win32WindowCore>(mCoreSpecific);
 	}
 	}
 
 
-	void Win32Window::setSyncData(UINT8* buffer, UINT32 size)
+	void Win32Window::syncProperties()
 	{
 	{
-		assert(size == sizeof(mProperties));
-		
-		memcpy(&mProperties, buffer, size);
+		ScopedSpinLock lock(getCore()->mLock);
+		mProperties = getCore()->mSyncedProperties;
 	}
 	}
 
 
 	HWND Win32Window::getHWnd() const
 	HWND Win32Window::getHWnd() const

+ 23 - 0
BansheeUtility/Include/BsSpinLock.h

@@ -40,4 +40,27 @@ namespace BansheeEngine
 	private:
 	private:
 		std::atomic_flag mLock;
 		std::atomic_flag mLock;
 	};
 	};
+
+	/**
+	 * @brief	Provides a safer method for locking a spin lock as the lock
+	 *			will get automatically locked when this objected is created and
+	 *			unlocked as soon as it goes out of scope.
+	 */
+	class ScopedSpinLock
+	{
+	public:
+		ScopedSpinLock(SpinLock& spinLock)
+			:mSpinLock(spinLock)
+		{
+			mSpinLock.lock();
+		}
+
+		~ScopedSpinLock()
+		{
+			mSpinLock.unlock();
+		}
+
+	private:
+		SpinLock& mSpinLock;
+	};
 }
 }

+ 18 - 0
MBansheeEditor/DebugWindow.cs

@@ -11,6 +11,8 @@ namespace BansheeEditor
 {
 {
     internal class DebugWindow : EditorWindow
     internal class DebugWindow : EditorWindow
     {
     {
+        bool debugSlowDown = false;
+
         private void OnInitialize()
         private void OnInitialize()
         {
         {
             GUIButton refreshAssembly = new GUIButton("Refresh assembly");
             GUIButton refreshAssembly = new GUIButton("Refresh assembly");
@@ -19,8 +21,12 @@ namespace BansheeEditor
             GUIButton compileGame = new GUIButton("Compile game assembly");
             GUIButton compileGame = new GUIButton("Compile game assembly");
             compileGame.OnClick += CompileGame_OnClick;
             compileGame.OnClick += CompileGame_OnClick;
 
 
+            GUIButton openColorPicker = new GUIButton("Color picker");
+            openColorPicker.OnClick += OpenColorPicker;
+
             GUI.layout.AddElement(refreshAssembly);
             GUI.layout.AddElement(refreshAssembly);
             GUI.layout.AddElement(compileGame);
             GUI.layout.AddElement(compileGame);
+            GUI.layout.AddElement(openColorPicker);
 
 
             GUIButton testExplicitBtn = new GUIButton("TESTING EXPLICIT");
             GUIButton testExplicitBtn = new GUIButton("TESTING EXPLICIT");
             testExplicitBtn.Bounds = compileGame.Bounds;
             testExplicitBtn.Bounds = compileGame.Bounds;
@@ -58,6 +64,18 @@ namespace BansheeEditor
                 Debug.Log("WARNING: " + ci.WarningMessages[i].file + ": " + ci.WarningMessages[i].line + " - " + ci.WarningMessages[i].message);
                 Debug.Log("WARNING: " + ci.WarningMessages[i].file + ": " + ci.WarningMessages[i].line + " - " + ci.WarningMessages[i].message);
         }
         }
 
 
+        void OpenColorPicker()
+        {
+            ColorPicker.Show();
+            debugSlowDown = true;
+        }
+
+        void EditorUpdate()
+        {
+            //if (debugSlowDown)
+            //    Thread.Sleep(5000);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern void Internal_RefreshAssembly();
         internal static extern void Internal_RefreshAssembly();
     }
     }

+ 29 - 10
TODO.txt

@@ -75,14 +75,39 @@ Other simple stuff:
  - Get rid of event callback from HString and figure out a better way
  - Get rid of event callback from HString and figure out a better way
  - GUI TextureField similar to ResourceField but it displays the texture it has assigned
  - GUI TextureField similar to ResourceField but it displays the texture it has assigned
  - Getting rid of import on start would be a pretty big deal. Just adding a button in Editor "Reimport" should be good instead
  - Getting rid of import on start would be a pretty big deal. Just adding a button in Editor "Reimport" should be good instead
+ - Better handle and gizmo shaders
+
+Focus issues:
+ISSUE #1:
+It seems that windows focus change can happen within Input::update. This is due to the fact that the message loop 
+runs on the core thread. When this happens, Input::update() triggers the input event (more specifically pointerPressed event) 
+that EditorWidgetManager is listening for. However the actual focus change wasn't registered with the sim thread yet because 
+RenderWindowManager::update() already happened this frame. This causes EditorWidgetManager to not assign focus to any widget 
+(because it thinks the clicked on render window doesn't have focus).
+ - Potential solution for this and issue #2: Separate input polling and callbacks. Have render window update happen after polling
+   but before callbacks. This way the focus status will properly set. Also it probably makes more sense to trigger input callbacks
+   at about the same time when Component::update calls are sent out.
+ - Potential solution: Do input polling on the core thread. i.e. call OISInput::update and OSInput::update from the core thread.
+   This might require a slight refactor of OSInput (or Platform) so it caches OS events differently.
+ - ADDITIONAL ISSUE: When relying on pointerPressed if the subscriber receives it before EditorWidgetManager it will seem as if
+   window isn't in focus. I need to somehow give priority to EditorWidgetManager.
+      - Solution: If I make sure Input callbacks are triggered after Input polling (i.e. when button states for this frame have already been set)
+	    I can make EditorWidgetManager rely on polling so it retrieves the state before any other system.
+ - ADDITIONAL ISSUE: When updating input on the core thread it can happen that the current frame is mid-Platform::update in which
+   case we'll get partial input from that update. How to handle this? If I only allow input from previous Platform::update to trigger
+   will that work? (i.e. not cause input lag). I say we do this anyway.
+
+ISSUE #2 (needs verification):
+When clicking on an unfocused EditorWindow the mouse down event will be registered but the window will still be marked as not
+in focus. It receives focus properly next frame. It's possible mouse up event happens on that same frame, causing additional randomness.
+
+ISSUE #3 (needs verification):
+When clicking on an unfocused EditorWindow it seems that button up event for LMB (possibly other keys) rarely doesn't ever get triggered. This goes
+as deep as Input class, possibly a problem in OIS.
 
 
 Minor issues:
 Minor issues:
  - When opening up Color picker it is screwed up for a frame or two
  - When opening up Color picker it is screwed up for a frame or two
- - When selecting a mesh, handle shows up first, and only then the selection render
- - When initially loading the program mesh texture is screwed up for a frame or two (OpenGL - garbage, DX9 - black, DX11 - seems okay)
  - Attemping to select a mesh while another window is focused doesn't work. Only after first click focuses the window will it work after user clicks again. (OpenGL only?)
  - Attemping to select a mesh while another window is focused doesn't work. Only after first click focuses the window will it work after user clicks again. (OpenGL only?)
- - Grid depth is wrong
- - Grid jaggies seem worse than on my test grid
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Handles
 Handles
@@ -120,12 +145,6 @@ Constant errors when rendering in DX11, and assert in DX9 when attempting to bin
 Check in new grid and selection shaders
 Check in new grid and selection shaders
  - Test DX9 grid shader
  - Test DX9 grid shader
 
 
-Test selection DX9 and DX11
-
-Grid shader:
- - Jaggies are significantly more noticable here than in Unity
- - It doesn't render properly when intersecting geometry
-
 Got a crash on shutdown that was caused by locking a mutex in an Event destructor. Event was Platform::onMouseCaptureChanged. 
 Got a crash on shutdown that was caused by locking a mutex in an Event destructor. Event was Platform::onMouseCaptureChanged. 
 Issue happened when I closed the app via the X button (if that's relevant). It doesn't seem to happen always.
 Issue happened when I closed the app via the X button (if that's relevant). It doesn't seem to happen always.