Browse Source

C# profiler overlay
Added generic key/value pairs to EditorSettings
Fixed an issue with VirtualInput where toggle states would reset immediately

Marko Pintera 10 years ago
parent
commit
ddef406ac9
34 changed files with 749 additions and 85 deletions
  1. 64 0
      BansheeEditor/Include/BsEditorSettings.h
  2. 0 8
      BansheeEditor/Source/BsEditorApplication.cpp
  3. 115 2
      BansheeEditor/Source/BsEditorSettings.cpp
  4. 1 1
      BansheeEngine/Include/BsDragAndDropManager.h
  5. 1 0
      BansheeEngine/Include/BsPrerequisites.h
  6. 44 4
      BansheeEngine/Include/BsProfilerOverlay.h
  7. 1 0
      BansheeEngine/Include/BsVirtualInput.h
  8. 2 2
      BansheeEngine/Source/BsDragAndDropManager.cpp
  9. 1 1
      BansheeEngine/Source/BsLightInternal.cpp
  10. 63 32
      BansheeEngine/Source/BsProfilerOverlay.cpp
  11. 7 0
      BansheeEngine/Source/BsVirtualInput.cpp
  12. 11 11
      BansheeOISInput/Include/BsInputHandlerOIS.h
  13. 2 2
      BansheeOISInput/Source/BsInputHandlerOIS.cpp
  14. 2 0
      BansheeUtility/Include/BsSphere.h
  15. 1 1
      BansheeUtility/Include/BsTime.h
  16. 1 1
      ExampleProject/Main/Main.cpp
  17. 2 0
      MBansheeEditor/EditorApplication.cs
  18. 80 0
      MBansheeEditor/EditorSettings.cs
  19. 0 8
      MBansheeEditor/ProjectWindow.cs
  20. 34 0
      MBansheeEditor/Scene/SceneWindow.cs
  21. 2 0
      MBansheeEngine/MBansheeEngine.csproj
  22. 43 0
      MBansheeEngine/ProfilerOverlay.cs
  23. 47 0
      MBansheeEngine/ProfilerOverlayInternal.cs
  24. 2 2
      MBansheeEngine/Time.cs
  25. 15 0
      SBansheeEditor/Include/BsScriptEditorSettings.h
  26. 3 3
      SBansheeEditor/Source/BsScriptDragDropManager.cpp
  27. 100 0
      SBansheeEditor/Source/BsScriptEditorSettings.cpp
  28. 4 4
      SBansheeEngine/Include/BsScriptComponent.h
  29. 27 0
      SBansheeEngine/Include/BsScriptProfilerOverlayInternal.h
  30. 1 1
      SBansheeEngine/Include/BsScriptTime.h
  31. 2 0
      SBansheeEngine/SBansheeEngine.vcxproj
  32. 6 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  33. 63 0
      SBansheeEngine/Source/BsScriptProfilerOverlayInternal.cpp
  34. 2 2
      SBansheeEngine/Source/BsScriptTime.cpp

+ 64 - 0
BansheeEditor/Include/BsEditorSettings.h

@@ -115,6 +115,65 @@ namespace BansheeEngine
 		 */
 		void setActivePivotMode(UINT32 value) { mActivePivotMode = value; markAsDirty(); }
 
+		/**
+		 * @brief	Adds or updates a property key/value pair with a floating point value.
+		 */
+		void setFloat(const String& name, float value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a signed integer value.
+		 */
+		void setInt(const String& name, INT32 value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a boolean value.
+		 */
+		void setBool(const String& name, bool value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a string value.
+		 */
+		void setString(const String& name, const WString& value);
+
+		/**
+		 * @brief	Returns the floating point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		float getFloat(const String& name, float defaultValue = 0.0f);
+
+		/**
+		 * @brief	Returns the integer point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		INT32 getInt(const String& name, INT32 defaultValue = 0);
+
+		/**
+		 * @brief	Returns the boolean point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		bool getBool(const String& name, bool defaultValue = false);
+
+		/**
+		 * @brief	Returns the string point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		WString getString(const String& name, const WString& defaultValue = StringUtil::WBLANK);
+
+		/**
+		 * @brief	Returns true if the key with the specified name exists.
+		 */
+		bool hasKey(const String& name);
+
+		/**
+		 * @brief	Deletes a key with the specified name.
+		 */
+		void deleteKey(const String& name);
+
+		/**
+		 * @brief	Deletes all key/value pairs.
+		 */
+		void deleteAllKeys();
+
 		/**
 		 * @brief	Returns a hash value that may be used for checking if any internal settings were
 		 *			modified.
@@ -142,6 +201,11 @@ namespace BansheeEngine
 
 		float mHandleSize;
 
+		Map<String, float> mFloatProperties;
+		Map<String, INT32> mIntProperties;
+		Map<String, bool> mBoolProperties;
+		Map<String, WString> mStringProperties;
+
 		mutable UINT32 mHash;
 	};
 }

+ 0 - 8
BansheeEditor/Source/BsEditorApplication.cpp

@@ -19,8 +19,6 @@
 #include "BsDropDownWindowManager.h"
 
 // DEBUG ONLY
-#include "DbgEditorWidget1.h"
-#include "DbgEditorWidget2.h"
 #include "BsResources.h"
 #include "BsSceneObject.h"
 #include "BsImporter.h"
@@ -31,7 +29,6 @@
 #include "BsTechnique.h"
 #include "BsPass.h"
 #include "BsRenderable.h"
-#include "BsDbgTestGameObjectRef.h"
 #include "BsVirtualInput.h"
 #include "BsFolderMonitor.h"
 #include "BsProjectLibrary.h"
@@ -197,12 +194,7 @@ namespace BansheeEngine
 		testRenderable->setMesh(mDbgMeshRef);
 		testRenderable->setMaterial(0, mTestMaterial);
 
-		GameObjectHandle<DbgTestGameObjectRef> dbgTestGameObjectRef = testModelGO->addComponent<DbgTestGameObjectRef>();
-		dbgTestGameObjectRef->mRenderable = testRenderable;
-
 		HSceneObject clone = testModelGO->clone();
-		GameObjectHandle<DbgTestGameObjectRef> clonedDbgTestGameObjectRef = clone->getComponent<DbgTestGameObjectRef>();
-
 		testModelGO->destroy();
 
 		/************************************************************************/

+ 115 - 2
BansheeEditor/Source/BsEditorSettings.cpp

@@ -3,8 +3,121 @@
 namespace BansheeEngine
 {
 	EditorSettings::EditorSettings()
-		:mMoveSnapActive(false), mRotateSnapActive(false), mMoveSnap(0.1f), mRotationSnap(20.0f), 
-		mGridSize(256), mGridAxisSpacing(1.0f), mHandleSize(0.10f), mHash(0), mActiveSceneTool(1 /* Move */), 
+		:mMoveSnapActive(false), mRotateSnapActive(false), mMoveSnap(0.1f), mRotationSnap(20.0f),
+		mGridSize(256), mGridAxisSpacing(1.0f), mHandleSize(0.10f), mHash(0), mActiveSceneTool(1 /* Move */),
 		mActiveCoordinateMode(0), mActivePivotMode(0)
 	{ }
+
+	void EditorSettings::setFloat(const String& name, float value)
+	{
+		mFloatProperties[name] = value;
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void EditorSettings::setInt(const String& name, INT32 value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties[name] = value;
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void EditorSettings::setBool(const String& name, bool value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties[name] = value; 
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void EditorSettings::setString(const String& name, const WString& value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties[name] = value;
+
+		markAsDirty();
+	}
+
+	float EditorSettings::getFloat(const String& name, float defaultValue)
+	{
+		auto iterFind = mFloatProperties.find(name);
+		if (iterFind != mFloatProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	INT32 EditorSettings::getInt(const String& name, INT32 defaultValue)
+	{
+		auto iterFind = mIntProperties.find(name);
+		if (iterFind != mIntProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	bool EditorSettings::getBool(const String& name, bool defaultValue)
+	{
+		auto iterFind = mBoolProperties.find(name);
+		if (iterFind != mBoolProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	WString EditorSettings::getString(const String& name, const WString& defaultValue)
+	{
+		auto iterFind = mStringProperties.find(name);
+		if (iterFind != mStringProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	bool EditorSettings::hasKey(const String& name)
+	{
+		if (mFloatProperties.find(name) != mFloatProperties.end())
+			return true;
+		
+		if (mIntProperties.find(name) != mIntProperties.end())
+			return true;
+
+		if (mBoolProperties.find(name) != mBoolProperties.end())
+			return true;
+
+		if (mStringProperties.find(name) != mStringProperties.end())
+			return true;
+
+		return false;
+	}
+
+	void EditorSettings::deleteKey(const String& name)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void EditorSettings::deleteAllKeys()
+	{
+		mFloatProperties.clear();
+		mIntProperties.clear();
+		mBoolProperties.clear();
+		mStringProperties.clear();
+
+		markAsDirty();
+	}
 }

+ 1 - 1
BansheeEngine/Include/BsDragAndDropManager.h

@@ -127,6 +127,6 @@ namespace BansheeEngine
 
 		std::atomic<bool> mCaptureChanged;
 		std::atomic<int> mCaptureActive;
-		std::atomic<unsigned long> mCaptureChangeFrame;
+		std::atomic<UINT64> mCaptureChangeFrame;
 	};
 }

+ 1 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -84,6 +84,7 @@ namespace BansheeEngine
 
 	class RenderableController;
 	class ProfilerOverlay;
+	class ProfilerOverlayInternal;
 	class DrawHelper;
 	class CameraHandler;
 	class RenderableHandler;

+ 44 - 4
BansheeEngine/Include/BsProfilerOverlay.h

@@ -8,6 +8,8 @@
 
 namespace BansheeEngine
 {
+	class ProfilerOverlayInternal;
+
 	/**
 	 * @brief	Types of profiler overlay.
 	 */
@@ -17,10 +19,48 @@ namespace BansheeEngine
 		GPUSamples
 	};
 
+	/**
+	* @brief	Handles rendering of Profiler information as an overlay in a viewport.
+	*			
+	* @note		Component wrapper of ProfilerOverlayInternal.
+	*/
+	class BS_EXPORT ProfilerOverlay : public Component
+	{
+	public:
+		/**
+		 * @brief	Constructs a new overlay attached to the specified parent and displayed on the provided viewport.
+		 */
+		ProfilerOverlay(const HSceneObject& parent, const ViewportPtr& target);
+		~ProfilerOverlay();
+
+		/**
+		 * @brief	Changes the viewport to display the overlay on.
+		 */
+		void setTarget(const ViewportPtr& target);
+
+		/**
+		 * @brief	Shows the overlay of the specified type.
+		 */
+		void show(ProfilerOverlayType type);
+
+		/**
+		 * @brief	Hides the overlay.
+		 */
+		void hide();
+
+		/**
+		 * @copydoc	Component::update
+		 */
+		void update() override;
+
+	private:
+		ProfilerOverlayInternal* mInternal;
+	};
+
 	/**
 	 * @brief	Handles rendering of Profiler information as an overlay in a viewport.
 	 */
-	class BS_EXPORT ProfilerOverlay : public Component
+	class BS_EXPORT ProfilerOverlayInternal
 	{
 	public:
 		/**
@@ -84,8 +124,8 @@ namespace BansheeEngine
 		/**
 		 * @brief	Constructs a new overlay attached to the specified parent and displayed on the provided viewport.
 		 */
-		ProfilerOverlay(const HSceneObject& parent, const ViewportPtr& target);
-		~ProfilerOverlay();
+		ProfilerOverlayInternal(const ViewportPtr& target);
+		~ProfilerOverlayInternal();
 
 		/**
 		 * @brief	Changes the viewport to display the overlay on.
@@ -103,7 +143,7 @@ namespace BansheeEngine
 		void hide();
 
 		/**
-		 * @copydoc	Component::update
+		 * @brief	Updates overlay contents. Should be called once per frame.
 		 */
 		void update();
 	private:

+ 1 - 0
BansheeEngine/Include/BsVirtualInput.h

@@ -32,6 +32,7 @@ namespace BansheeEngine
 			VirtualButton button;
 			ButtonState state;
 			UINT64 timestamp;
+			UINT64 updateFrameIdx;
 			bool allowRepeat;
 		};
 

+ 2 - 2
BansheeEngine/Source/BsDragAndDropManager.cpp

@@ -49,7 +49,7 @@ namespace BansheeEngine
 		// This generally happens when window loses focus and capture is lost (e.g. alt+tab)
 		int captureActive = mCaptureActive.load();
 		if (!captureActive && mCaptureChanged.load() && 
-			(gTime().getFrameNumber() > mCaptureChangeFrame.load())) // Wait one frame to insure input (like mouse up) gets a chance to be processed
+			(gTime().getFrameIdx() > mCaptureChangeFrame.load())) // Wait one frame to insure input (like mouse up) gets a chance to be processed
 		{
 			endDrag(false);
 			mCaptureChanged.store(false);
@@ -71,7 +71,7 @@ namespace BansheeEngine
 	{
 		mCaptureActive.fetch_xor(1); // mCaptureActive = !mCaptureActive;
 		mCaptureChanged.store(true);
-		mCaptureChangeFrame.store(gTime().getFrameNumber());
+		mCaptureChangeFrame.store(gTime().getFrameIdx());
 	}
 
 	void DragAndDropManager::cursorReleased(const PointerEvent& event)

+ 1 - 1
BansheeEngine/Source/BsLightInternal.cpp

@@ -229,7 +229,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void LightInternal::_markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything)
+	void LightInternal::_markCoreDirty(LightDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);
 	}

+ 63 - 32
BansheeEngine/Source/BsProfilerOverlay.cpp

@@ -23,9 +23,9 @@ namespace BansheeEngine
 		GUILayout& labelLayout;
 		GUILayout& contentLayout;
 		GUIWidget& widget;
-		Vector<ProfilerOverlay::BasicRow>& rows;
+		Vector<ProfilerOverlayInternal::BasicRow>& rows;
 
-		BasicRowFiller(Vector<ProfilerOverlay::BasicRow>& _rows, GUILayout& _labelLayout, GUILayout& _contentLayout, GUIWidget& _widget)
+		BasicRowFiller(Vector<ProfilerOverlayInternal::BasicRow>& _rows, GUILayout& _labelLayout, GUILayout& _contentLayout, GUIWidget& _widget)
 			:rows(_rows), curIdx(0), labelLayout(_labelLayout), contentLayout(_contentLayout), widget(_widget)
 		{ }
 
@@ -34,7 +34,7 @@ namespace BansheeEngine
 			UINT32 excessEntries = (UINT32)rows.size() - curIdx;
 			for(UINT32 i = 0; i < excessEntries; i++)
 			{
-				ProfilerOverlay::BasicRow& row = rows[curIdx + i];
+				ProfilerOverlayInternal::BasicRow& row = rows[curIdx + i];
 
 				GUILayout::destroy(row.labelLayout);
 				GUILayout::destroy(row.contentLayout);
@@ -48,9 +48,9 @@ namespace BansheeEngine
 		{
 			if(curIdx >= rows.size())
 			{
-				rows.push_back(ProfilerOverlay::BasicRow());
+				rows.push_back(ProfilerOverlayInternal::BasicRow());
 
-				ProfilerOverlay::BasicRow& newRow = rows.back();
+				ProfilerOverlayInternal::BasicRow& newRow = rows.back();
 
 				newRow.name = HString(L"{0}");
 				newRow.pctOfParent = HString(L"{0} %");
@@ -98,7 +98,7 @@ namespace BansheeEngine
 				newRow.elements.push_back(totalTimeSelf);
 			}
 			
-			ProfilerOverlay::BasicRow& row = rows[curIdx];
+			ProfilerOverlayInternal::BasicRow& row = rows[curIdx];
 
 			GUIFixedSpace::destroy(row.labelSpace);
 			row.labelSpace = row.labelLayout->insertNewElement<GUIFixedSpace>(0, depth * 20);
@@ -124,9 +124,9 @@ namespace BansheeEngine
 		GUILayout& labelLayout;
 		GUILayout& contentLayout;
 		GUIWidget& widget;
-		Vector<ProfilerOverlay::PreciseRow>& rows;
+		Vector<ProfilerOverlayInternal::PreciseRow>& rows;
 
-		PreciseRowFiller(Vector<ProfilerOverlay::PreciseRow>& _rows, GUILayout& _labelLayout, GUILayout& _contentLayout, GUIWidget& _widget)
+		PreciseRowFiller(Vector<ProfilerOverlayInternal::PreciseRow>& _rows, GUILayout& _labelLayout, GUILayout& _contentLayout, GUIWidget& _widget)
 			:rows(_rows), curIdx(0), labelLayout(_labelLayout), contentLayout(_contentLayout), widget(_widget)
 		{ }
 
@@ -135,7 +135,7 @@ namespace BansheeEngine
 			UINT32 excessEntries = (UINT32)rows.size() - curIdx;
 			for(UINT32 i = 0; i < excessEntries; i++)
 			{
-				ProfilerOverlay::PreciseRow& row = rows[curIdx + i];
+				ProfilerOverlayInternal::PreciseRow& row = rows[curIdx + i];
 
 				GUILayout::destroy(row.labelLayout);
 				GUILayout::destroy(row.contentLayout);
@@ -149,9 +149,9 @@ namespace BansheeEngine
 		{
 			if(curIdx >= rows.size())
 			{
-				rows.push_back(ProfilerOverlay::PreciseRow());
+				rows.push_back(ProfilerOverlayInternal::PreciseRow());
 
-				ProfilerOverlay::PreciseRow& newRow = rows.back();
+				ProfilerOverlayInternal::PreciseRow& newRow = rows.back();
 
 				newRow.name = HString(L"{0}");
 				newRow.pctOfParent = HString(L"{0}");
@@ -199,7 +199,7 @@ namespace BansheeEngine
 				newRow.elements.push_back(totalCyclesSelf);
 			}
 
-			ProfilerOverlay::PreciseRow& row = rows[curIdx];
+			ProfilerOverlayInternal::PreciseRow& row = rows[curIdx];
 
 			GUIFixedSpace::destroy(row.labelSpace);
 			row.labelSpace = row.labelLayout->insertNewElement<GUIFixedSpace>(0, depth * 20);
@@ -224,9 +224,9 @@ namespace BansheeEngine
 		UINT32 curIdx;
 		GUILayout& layout;
 		GUIWidget& widget;
-		Vector<ProfilerOverlay::GPUSampleRow>& rows;
+		Vector<ProfilerOverlayInternal::GPUSampleRow>& rows;
 
-		GPUSampleRowFiller(Vector<ProfilerOverlay::GPUSampleRow>& _rows, GUILayout& _layout, GUIWidget& _widget)
+		GPUSampleRowFiller(Vector<ProfilerOverlayInternal::GPUSampleRow>& _rows, GUILayout& _layout, GUIWidget& _widget)
 			:rows(_rows), curIdx(0), layout(_layout), widget(_widget)
 		{ }
 
@@ -235,7 +235,7 @@ namespace BansheeEngine
 			UINT32 excessEntries = (UINT32)rows.size() - curIdx;
 			for (UINT32 i = 0; i < excessEntries; i++)
 			{
-				ProfilerOverlay::GPUSampleRow& row = rows[curIdx + i];
+				ProfilerOverlayInternal::GPUSampleRow& row = rows[curIdx + i];
 
 				GUILayout::destroy(row.layout);
 			}
@@ -247,9 +247,9 @@ namespace BansheeEngine
 		{
 			if (curIdx >= rows.size())
 			{
-				rows.push_back(ProfilerOverlay::GPUSampleRow());
+				rows.push_back(ProfilerOverlayInternal::GPUSampleRow());
 
-				ProfilerOverlay::GPUSampleRow& newRow = rows.back();
+				ProfilerOverlayInternal::GPUSampleRow& newRow = rows.back();
 
 				newRow.name = HString(L"{1}");
 				newRow.time = HString(L"{0}");
@@ -266,7 +266,7 @@ namespace BansheeEngine
 				newRow.elements.push_back(timeLabel);
 			}
 
-			ProfilerOverlay::GPUSampleRow& row = rows[curIdx];
+			ProfilerOverlayInternal::GPUSampleRow& row = rows[curIdx];
 			row.name.setParameter(0, toWString(name));
 			row.time.setParameter(0, toWString(timeMs));
 
@@ -274,15 +274,46 @@ namespace BansheeEngine
 		}
 	};
 
-	const UINT32 ProfilerOverlay::MAX_DEPTH = 4;
+	const UINT32 ProfilerOverlayInternal::MAX_DEPTH = 4;
 
 	ProfilerOverlay::ProfilerOverlay(const HSceneObject& parent, const ViewportPtr& target)
-		:Component(parent), mIsShown(false), mType(ProfilerOverlayType::CPUSamples)
+		:Component(parent), mInternal(nullptr)
 	{
-		setTarget(target);
+		mInternal = bs_new<ProfilerOverlayInternal>(target);
 	}
 
 	ProfilerOverlay::~ProfilerOverlay()
+	{
+		bs_delete(mInternal);
+	}
+
+	void ProfilerOverlay::setTarget(const ViewportPtr& target)
+	{
+		mInternal->setTarget(target);
+	}
+
+	void ProfilerOverlay::show(ProfilerOverlayType type)
+	{
+		mInternal->show(type);
+	}
+
+	void ProfilerOverlay::hide()
+	{
+		mInternal->hide();
+	}
+
+	void ProfilerOverlay::update()
+	{
+		mInternal->update();
+	}
+
+	ProfilerOverlayInternal::ProfilerOverlayInternal(const ViewportPtr& target)
+		:mIsShown(true), mType(ProfilerOverlayType::CPUSamples)
+	{
+		setTarget(target);
+	}
+
+	ProfilerOverlayInternal::~ProfilerOverlayInternal()
 	{
 		if(mTarget != nullptr)
 			mTargetResizedConn.disconnect();
@@ -291,14 +322,14 @@ namespace BansheeEngine
 			mWidgetSO->destroy();
 	}
 
-	void ProfilerOverlay::setTarget(const ViewportPtr& target)
+	void ProfilerOverlayInternal::setTarget(const ViewportPtr& target)
 	{
 		if(mTarget != nullptr)
 			mTargetResizedConn.disconnect();
 
 		mTarget = target;
 
-		mTargetResizedConn = target->getTarget()->onResized.connect(std::bind(&ProfilerOverlay::targetResized, this));
+		mTargetResizedConn = target->getTarget()->onResized.connect(std::bind(&ProfilerOverlayInternal::targetResized, this));
 
 		if(mWidgetSO)
 			mWidgetSO->destroy();
@@ -451,7 +482,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void ProfilerOverlay::show(ProfilerOverlayType type)
+	void ProfilerOverlayInternal::show(ProfilerOverlayType type)
 	{
 		if (type == ProfilerOverlayType::CPUSamples)
 		{
@@ -476,7 +507,7 @@ namespace BansheeEngine
 		mIsShown = true;
 	}
 
-	void ProfilerOverlay::hide()
+	void ProfilerOverlayInternal::hide()
 	{
 		mBasicLayoutLabels->disableRecursively();
 		mPreciseLayoutLabels->disableRecursively();
@@ -487,7 +518,7 @@ namespace BansheeEngine
 		mIsShown = false;
 	}
 
-	void ProfilerOverlay::update()
+	void ProfilerOverlayInternal::update()
 	{
 		const ProfilerReport& latestSimReport = ProfilingManager::instance().getReport(ProfiledThread::Sim);
 		const ProfilerReport& latestCoreReport = ProfilingManager::instance().getReport(ProfiledThread::Core);
@@ -503,13 +534,13 @@ namespace BansheeEngine
 		}
 	}
 
-	void ProfilerOverlay::targetResized()
+	void ProfilerOverlayInternal::targetResized()
 	{
 		updateCPUSampleAreaSizes();
 		updateGPUSampleAreaSizes();
 	}
 
-	void ProfilerOverlay::updateCPUSampleAreaSizes()
+	void ProfilerOverlayInternal::updateCPUSampleAreaSizes()
 	{
 		static const INT32 PADDING = 10;
 		static const float LABELS_CONTENT_RATIO = 0.3f;
@@ -537,7 +568,7 @@ namespace BansheeEngine
 		mPreciseLayoutContents->setHeight(height);
 	}
 
-	void ProfilerOverlay::updateGPUSampleAreaSizes()
+	void ProfilerOverlayInternal::updateGPUSampleAreaSizes()
 	{
 		static const INT32 PADDING = 10;
 		static const float SAMPLES_FRAME_RATIO = 0.5f;
@@ -557,7 +588,7 @@ namespace BansheeEngine
 		mGPULayoutSamples->setHeight(samplesHeight);
 	}
 
-	void ProfilerOverlay::updateCPUSampleContents(const ProfilerReport& simReport, const ProfilerReport& coreReport)
+	void ProfilerOverlayInternal::updateCPUSampleContents(const ProfilerReport& simReport, const ProfilerReport& coreReport)
 	{
 		static const UINT32 NUM_ROOT_ENTRIES = 2;
 
@@ -648,9 +679,9 @@ namespace BansheeEngine
 		}
 	}
 
-	void ProfilerOverlay::updateGPUSampleContents(const GPUProfilerReport& gpuReport)
+	void ProfilerOverlayInternal::updateGPUSampleContents(const GPUProfilerReport& gpuReport)
 	{
-		mGPUFrameNumStr.setParameter(0, toWString((UINT64)gTime().getFrameNumber()));
+		mGPUFrameNumStr.setParameter(0, toWString((UINT64)gTime().getFrameIdx()));
 		mGPUTimeStr.setParameter(0, toWString(gpuReport.frameSample.timeMs));
 		mGPUDrawCallsStr.setParameter(0, toWString(gpuReport.frameSample.numDrawCalls));
 		mGPURenTargetChangesStr.setParameter(0, toWString(gpuReport.frameSample.numRenderTargetChanges));

+ 7 - 0
BansheeEngine/Source/BsVirtualInput.cpp

@@ -102,10 +102,15 @@ namespace BansheeEngine
 
 	void VirtualInput::_update()
 	{
+		UINT64 frameIdx = gTime().getFrameIdx();
 		for (auto& deviceData : mDevices)
 		{
 			for (auto& state : deviceData.cachedStates)
 			{
+				// We need to stay in toggled state for one frame.
+				if (state.second.updateFrameIdx == frameIdx)
+					continue;
+
 				if (state.second.state == ButtonState::ToggledOff)
 					state.second.state = ButtonState::Off;
 				else if (state.second.state == ButtonState::ToggledOn)
@@ -194,6 +199,7 @@ namespace BansheeEngine
 				data.button = btn;
 				data.state = ButtonState::ToggledOn;
 				data.timestamp = event.timestamp;
+				data.updateFrameIdx = gTime().getFrameIdx();
 				data.allowRepeat = btnDesc.repeatable;
 
 				VirtualButtonEvent virtualEvent;
@@ -229,6 +235,7 @@ namespace BansheeEngine
 				data.button = btn;
 				data.state = ButtonState::ToggledOff;
 				data.timestamp = event.timestamp;
+				data.updateFrameIdx = gTime().getFrameIdx();
 				data.allowRepeat = btnDesc.repeatable;
 
 				VirtualButtonEvent virtualEvent;

+ 11 - 11
BansheeOISInput/Include/BsInputHandlerOIS.h

@@ -24,17 +24,17 @@ namespace BansheeEngine
 		/**
 		 * @brief	Called by OIS whenever a gamepad/joystick button is pressed.
 		 */
-		virtual bool buttonPressed(const OIS::JoyStickEvent& arg, int button);
+		virtual bool buttonPressed(const OIS::JoyStickEvent& arg, int button) override;
 
 		/**
 		 * @brief	Called by OIS whenever a gamepad/joystick button is released.
 		 */
-		virtual bool buttonReleased(const OIS::JoyStickEvent& arg, int button);
+		virtual bool buttonReleased(const OIS::JoyStickEvent& arg, int button) override;
 
 		/**
 		 * @brief	Called by OIS whenever a gamepad/joystick axis is moved.
 		 */
-		virtual bool axisMoved(const OIS::JoyStickEvent& arg, int axis);
+		virtual bool axisMoved(const OIS::JoyStickEvent& arg, int axis) override;
 
 	private:
 		UINT32 mGamepadIdx;
@@ -64,41 +64,41 @@ namespace BansheeEngine
 		/**
 		 * @brief	Called by OIS whenever a keyboard button is pressed.
 		 */
-		virtual bool keyPressed(const OIS::KeyEvent& arg);
+		virtual bool keyPressed(const OIS::KeyEvent& arg) override;
 
 		/**
 		 * @brief	Called by OIS whenever a keyboard button is released.
 		 */
-		virtual bool keyReleased(const OIS::KeyEvent& arg);
+		virtual bool keyReleased(const OIS::KeyEvent& arg) override;
 
 		/**
 		 * @brief	Called by OIS whenever mouse is moved.
 		 */
-		virtual bool mouseMoved(const OIS::MouseEvent& arg);
+		virtual bool mouseMoved(const OIS::MouseEvent& arg) override;
 
 		/**
 		 * @brief	Called by OIS whenever is a mouse button pressed.
 		 */
-		virtual bool mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
+		virtual bool mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id) override;
 
 		/**
 		 * @brief	Called by OIS whenever is a mouse button released
 		 */
-		virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
+		virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id) override;
 
 		/**
 		 * @brief	Called once per frame.
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _update();
+		virtual void _update() override;
 
 		/**
 		 * @brief	Called whenever the currently focused window changes.
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _inputWindowChanged(const RenderWindow& win);
+		virtual void _inputWindowChanged(const RenderWindow& win) override;
 
 		/**
 		 * @brief	Converts an OIS key code into engine button code.
@@ -139,7 +139,7 @@ namespace BansheeEngine
 		float mMouseZeroTime[2];
 		INT32 mMouseSampleAccumulator[2];
 		float mMouseSmoothedAxis[2];
-		UINT32 mLastMouseUpdateFrame;
+		UINT64 mLastMouseUpdateFrame;
 
 		UINT64 mTimestampClockOffset;
 	};

+ 2 - 2
BansheeOISInput/Source/BsInputHandlerOIS.cpp

@@ -255,7 +255,7 @@ namespace BansheeEngine
 
 		// Update sample times used for determining sampling rate. But only if something was
 		// actually sampled, and only if this isn't the first non-zero sample.
-		if (mLastMouseUpdateFrame != gTime().getFrameNumber())
+		if (mLastMouseUpdateFrame != gTime().getFrameIdx())
 		{
 			if (arg.state.X.rel != 0 && !Math::approxEquals(mMouseSmoothedAxis[0], 0.0f))
 				mTotalMouseSamplingTime[0] += gTime().getFrameDelta();
@@ -263,7 +263,7 @@ namespace BansheeEngine
 			if (arg.state.Y.rel != 0 && !Math::approxEquals(mMouseSmoothedAxis[1], 0.0f))
 				mTotalMouseSamplingTime[1] += gTime().getFrameDelta();
 
-			mLastMouseUpdateFrame = gTime().getFrameNumber();
+			mLastMouseUpdateFrame = gTime().getFrameIdx();
 		}
 
 		RawAxisState zState;

+ 2 - 0
BansheeUtility/Include/BsSphere.h

@@ -97,4 +97,6 @@ namespace BansheeEngine
 		float mRadius;
 		Vector3 mCenter;
     };
+
+	BS_ALLOW_MEMCPY_SERIALIZATION(Sphere);
 }

+ 1 - 1
BansheeUtility/Include/BsTime.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Thread safe, but only counts sim thread frames.
 		 */
-		unsigned long getFrameNumber() const { return mCurrentFrame.load(); }
+		UINT64 getFrameIdx() const { return mCurrentFrame.load(); }
 
 		/**
 		 * @brief	Returns the precise time since application start, in microseconds.

+ 1 - 1
ExampleProject/Main/Main.cpp

@@ -361,7 +361,7 @@ namespace BansheeEngine
 		// Leave 30 pixels to the right free
 		rightLayout->addNewElement<GUIFixedSpace>(30);
 
-		// Add a profiler overlay object that is resposible for displaying CPU and GPU profiling GUI
+		// Add a profiler overlay object that is responsible for displaying CPU and GPU profiling GUI
 		profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->getViewport());
 
 		// Set up video mode list box

+ 2 - 0
MBansheeEditor/EditorApplication.cs

@@ -99,6 +99,8 @@ namespace BansheeEditor
             inputConfig.RegisterAxis(SceneCamera.HorizontalAxisBinding, InputAxis.MouseX);
             inputConfig.RegisterAxis(SceneCamera.VerticalAxisBinding, InputAxis.MouseY);
 
+            inputConfig.RegisterButton(SceneWindow.ToggleProfilerOverlayBinding, ButtonCode.P, ButtonModifier.CtrlAlt);
+
             ProjectLibrary.Refresh();
             monitor = new FolderMonitor(ProjectLibrary.ResourceFolder);
             monitor.OnAdded += OnAssetModified;

+ 80 - 0
MBansheeEditor/EditorSettings.cs

@@ -58,6 +58,61 @@ namespace BansheeEditor
             set { Internal_SetActivePivotMode((int)value); }
         }
 
+        public static void SetFloat(string name, float value)
+        {
+            Internal_SetFloat(name, value);
+        }
+
+        public static void SetInt(string name, int value)
+        {
+            Internal_SetInt(name, value);
+        }
+
+        public static void SetBool(string name, bool value)
+        {
+            Internal_SetBool(name, value);
+        }
+
+        public static void SetString(string name, String value)
+        {
+            Internal_SetString(name, value);
+        }
+
+        public static float GetFloat(string name, float defaultValue = 0.0f)
+        {
+            return Internal_GetFloat(name, defaultValue);
+        }
+
+        public static int GetInt(string name, int defaultValue = 0)
+        {
+            return Internal_GetInt(name, defaultValue);
+        }
+
+        public static bool GetBool(string name, bool defaultValue = false)
+        {
+            return Internal_GetBool(name, defaultValue);
+        }
+
+        public static String GetString(string name, string defaultValue = "")
+        {
+            return Internal_GetString(name, defaultValue);
+        }
+
+        public static bool HasKey(string name)
+        {
+            return Internal_HasKey(name);
+        }
+
+        public static void DeleteKey(string name)
+        {
+            Internal_DeleteKey(name);
+        }
+
+        public static void DeleteAllKeys()
+        {
+            Internal_DeleteAllKeys();
+        }
+
         public static int Hash
         {
             get { return Internal_GetHash(); }
@@ -103,6 +158,31 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetActivePivotMode(int value);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetFloat(string name, float value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetInt(string name, int value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBool(string name, bool value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetString(string name, String value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetFloat(string name, float defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetInt(string name, int defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetBool(string name, bool defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetString(string name, string defaultValue);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_HasKey(string name);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DeleteKey(string name);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DeleteAllKeys();
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern int Internal_GetHash();
     }

+ 0 - 8
MBansheeEditor/ProjectWindow.cs

@@ -864,14 +864,6 @@ namespace BansheeEditor
             }
             else
             {
-                int tileSize = 64;
-                switch (viewType)
-                {
-                    case ProjectViewType.Grid64: tileSize = 64; break;
-                    case ProjectViewType.Grid48: tileSize = 48; break;
-                    case ProjectViewType.Grid32: tileSize = 32; break;
-                }
-
                 contentInfo.main.AddSpace(GRID_ENTRY_SPACING / 2);
                 GUILayoutX rowLayout = contentInfo.main.AddLayoutX();
                 contentInfo.main.AddSpace(GRID_ENTRY_SPACING);

+ 34 - 0
MBansheeEditor/Scene/SceneWindow.cs

@@ -10,9 +10,12 @@ namespace BansheeEditor
 {
     internal sealed class SceneWindow : EditorWindow
     {
+        internal const string ToggleProfilerOverlayBinding = "ToggleProfilerOverlay";
+
         private const int HeaderHeight = 20;
         private const float DefaultPlacementDepth = 5.0f;
         private static readonly Color ClearColor = new Color(83.0f/255.0f, 83.0f/255.0f, 83.0f/255.0f);
+        private const string ProfilerOverlayActiveKey = "_Internal_ProfilerOverlayActive";
 
         private Camera camera;
         private SceneCamera cameraController;
@@ -41,6 +44,10 @@ namespace BansheeEditor
 
         private int editorSettingsHash = int.MaxValue;
 
+        // Profiler overlay
+        private ProfilerOverlay activeProfilerOverlay;
+        private VirtualButton toggleProfilerOverlayKey;
+
         // Drag & drop
         private bool dragActive;
         private SceneObject draggedSO;
@@ -123,7 +130,10 @@ namespace BansheeEditor
             handlesLayout.AddElement(rotateSnapButton);
             handlesLayout.AddElement(rotateSnapInput);
 
+            toggleProfilerOverlayKey = new VirtualButton(ToggleProfilerOverlayBinding);
+
             UpdateRenderTexture(Width, Height - HeaderHeight);
+            UpdateProfilerOverlay();
         }
 
         private void OnDestroy()
@@ -155,10 +165,17 @@ namespace BansheeEditor
 
         private void OnEditorUpdate()
         {
+            if (HasFocus)
+            {
+                if (VirtualInput.IsButtonUp(toggleProfilerOverlayKey))
+                    EditorSettings.SetBool(ProfilerOverlayActiveKey, !EditorSettings.GetBool(ProfilerOverlayActiveKey));
+            }
+
             // Refresh GUI buttons if needed (in case someones changes the values from script)
             if (editorSettingsHash != EditorSettings.Hash)
             {
                 UpdateButtonStates();
+                UpdateProfilerOverlay();
                 editorSettingsHash = EditorSettings.Hash;
             }
 
@@ -389,6 +406,23 @@ namespace BansheeEditor
             moveSnapInput.Value = Handles.RotateSnapAmount.Degrees;
         }
 
+        private void UpdateProfilerOverlay()
+        {
+            if (EditorSettings.GetBool(ProfilerOverlayActiveKey))
+            {
+                if (activeProfilerOverlay == null)
+                    activeProfilerOverlay = camera.SceneObject.AddComponent<ProfilerOverlay>();
+            }
+            else
+            {
+                if (activeProfilerOverlay != null)
+                {
+                    activeProfilerOverlay.SceneObject.RemoveComponent<ProfilerOverlay>();
+                    activeProfilerOverlay = null;
+                }
+            }
+        }
+
         private void UpdateRenderTexture(int width, int height)
 	    {
             width = MathEx.Max(20, width);

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -107,6 +107,8 @@
     <Compile Include="PixelUtility.cs" />
     <Compile Include="PlainText.cs" />
     <Compile Include="Prefab.cs" />
+    <Compile Include="ProfilerOverlay.cs" />
+    <Compile Include="ProfilerOverlayInternal.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Math\Quaternion.cs" />

+ 43 - 0
MBansheeEngine/ProfilerOverlay.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BansheeEngine
+{
+    // Note: Must be the same as C++ enum ProfilerOverlayType
+	public enum ProfilerOverlayType
+	{
+		CPUSamples,
+		GPUSamples
+	};
+
+    public class ProfilerOverlay : Component
+    {
+        private ProfilerOverlayInternal impl;
+
+        public void SetType(ProfilerOverlayType type)
+        {
+            impl.SetType(type);   
+        }
+
+        private void OnReset()
+        {
+            if (impl != null)
+                impl.Destroy();
+
+            Camera cam = SceneObject.GetComponent<Camera>();
+            impl = new ProfilerOverlayInternal(cam);
+        }
+
+        private void Update()
+        {
+            impl.Update();
+        }
+
+        private void OnDestroy()
+        {
+            impl.Destroy();
+        }
+    }
+}

+ 47 - 0
MBansheeEngine/ProfilerOverlayInternal.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace BansheeEngine
+{
+    internal class ProfilerOverlayInternal : ScriptObject
+    {
+        internal ProfilerOverlayInternal(Camera camera)
+        {
+            IntPtr ptr = IntPtr.Zero;
+            if (camera != null)
+                ptr = camera.Handler.GetCachedPtr();
+
+            Internal_CreateInstance(this, ptr);
+        }
+
+        public void SetType(ProfilerOverlayType type)
+        {
+            Internal_SetType(mCachedPtr, type);
+        }
+
+        internal void Update()
+        {
+            Internal_Update(mCachedPtr);
+        }
+
+        internal void Destroy()
+        {
+            Internal_DestroyInstance(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(ProfilerOverlayInternal instance, IntPtr cameraHandler);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetType(IntPtr instance, ProfilerOverlayType type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Update(IntPtr instance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DestroyInstance(IntPtr instance);
+    }
+}

+ 2 - 2
MBansheeEngine/Time.cs

@@ -18,7 +18,7 @@ namespace BansheeEngine
             get { return Internal_GetFrameDelta(); }
         }
 
-        public static int FrameNumber
+        public static UInt64 FrameIdx
         {
             get { return Internal_GetFrameNumber(); }
         }
@@ -38,7 +38,7 @@ namespace BansheeEngine
         private static extern float Internal_GetFrameDelta();
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetFrameNumber();
+        private static extern UInt64 Internal_GetFrameNumber();
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern UInt64 Internal_GetPrecise();

+ 15 - 0
SBansheeEditor/Include/BsScriptEditorSettings.h

@@ -29,6 +29,21 @@ namespace BansheeEngine
 		static void internal_SetActiveCoordinateMode(UINT32 value);
 		static UINT32 internal_GetActivePivotMode();
 		static void internal_SetActivePivotMode(UINT32 value);
+
+		static void internal_SetFloat(MonoString* name, float value);
+		static void internal_SetInt(MonoString* name, int value);
+		static void internal_SetBool(MonoString* name, bool value);
+		static void internal_SetString(MonoString* name, MonoString* value);
+
+		static float internal_GetFloat(MonoString* name, float defaultValue);
+		static int internal_GetInt(MonoString* name, int defaultValue);
+		static bool internal_GetBool(MonoString* name, bool defaultValue);
+		static MonoString* internal_GetString(MonoString* name, MonoString* defaultValue);
+
+		static bool internal_HasKey(MonoString* name);
+		static void internal_DeleteKey(MonoString* name);
+		static void internal_DeleteAllKeys();
+
 		static UINT32 internal_GetHash();
 	};
 }

+ 3 - 3
SBansheeEditor/Source/BsScriptDragDropManager.cpp

@@ -219,7 +219,7 @@ namespace BansheeEngine
 	void ScriptDragDropManager::update()
 	{
 		// This only stays active for a single frame
-		if (mIsDropInProgress && mDroppedFrameIdx < Time::instance().getFrameNumber())
+		if (mIsDropInProgress && mDroppedFrameIdx < Time::instance().getFrameIdx())
 			mIsDropInProgress = false;
 	}
 
@@ -295,7 +295,7 @@ namespace BansheeEngine
 
 			mIsDropInProgress = true;
 			mDropType = ScriptDragDropType::SceneObject;
-			mDroppedFrameIdx = Time::instance().getFrameNumber();
+			mDroppedFrameIdx = Time::instance().getFrameIdx();
 		}
 		else if (nativeType == (UINT32)DragAndDropType::Resources)
 		{
@@ -304,7 +304,7 @@ namespace BansheeEngine
 			mDroppedPaths = draggedResources->resourcePaths;
 			mIsDropInProgress = true;
 			mDropType = ScriptDragDropType::Resource;
-			mDroppedFrameIdx = Time::instance().getFrameNumber();
+			mDroppedFrameIdx = Time::instance().getFrameIdx();
 		}
 	}
 }

+ 100 - 0
SBansheeEditor/Source/BsScriptEditorSettings.cpp

@@ -30,6 +30,17 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetActiveCoordinateMode", &ScriptEditorSettings::internal_SetActiveCoordinateMode);
 		metaData.scriptClass->addInternalCall("Internal_GetActivePivotMode", &ScriptEditorSettings::internal_GetActivePivotMode);
 		metaData.scriptClass->addInternalCall("Internal_SetActivePivotMode", &ScriptEditorSettings::internal_SetActivePivotMode);
+		metaData.scriptClass->addInternalCall("Internal_SetFloat", &ScriptEditorSettings::internal_SetFloat);
+		metaData.scriptClass->addInternalCall("Internal_SetInt", &ScriptEditorSettings::internal_SetInt);
+		metaData.scriptClass->addInternalCall("Internal_SetBool", &ScriptEditorSettings::internal_SetBool);
+		metaData.scriptClass->addInternalCall("Internal_SetString", &ScriptEditorSettings::internal_SetString);
+		metaData.scriptClass->addInternalCall("Internal_GetFloat", &ScriptEditorSettings::internal_GetFloat);
+		metaData.scriptClass->addInternalCall("Internal_GetInt", &ScriptEditorSettings::internal_GetInt);
+		metaData.scriptClass->addInternalCall("Internal_GetBool", &ScriptEditorSettings::internal_GetBool);
+		metaData.scriptClass->addInternalCall("Internal_GetString", &ScriptEditorSettings::internal_GetString);
+		metaData.scriptClass->addInternalCall("Internal_HasKey", &ScriptEditorSettings::internal_HasKey);
+		metaData.scriptClass->addInternalCall("Internal_DeleteKey", &ScriptEditorSettings::internal_DeleteKey);
+		metaData.scriptClass->addInternalCall("Internal_DeleteAllKeys", &ScriptEditorSettings::internal_DeleteAllKeys);
 		metaData.scriptClass->addInternalCall("Internal_GetHash", &ScriptEditorSettings::internal_GetHash);
 	}
 
@@ -129,6 +140,95 @@ namespace BansheeEngine
 		settings->setActivePivotMode(value);
 	}
 
+	void ScriptEditorSettings::internal_SetFloat(MonoString* name, float value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setFloat(nativeName, value);
+	}
+
+	void ScriptEditorSettings::internal_SetInt(MonoString* name, int value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setInt(nativeName, value);
+	}
+
+	void ScriptEditorSettings::internal_SetBool(MonoString* name, bool value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setBool(nativeName, value);
+	}
+
+	void ScriptEditorSettings::internal_SetString(MonoString* name, MonoString* value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+		WString nativeValue = MonoUtil::monoToWString(value);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setString(nativeName, nativeValue);
+	}
+
+	float ScriptEditorSettings::internal_GetFloat(MonoString* name, float defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return settings->getFloat(nativeName);
+	}
+
+	int ScriptEditorSettings::internal_GetInt(MonoString* name, int defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return settings->getInt(nativeName);
+	}
+
+	bool ScriptEditorSettings::internal_GetBool(MonoString* name, bool defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return settings->getBool(nativeName);
+	}
+
+	MonoString* ScriptEditorSettings::internal_GetString(MonoString* name, MonoString* defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		WString nativeValue = settings->getString(nativeName);
+
+		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativeValue);
+	}
+
+	bool ScriptEditorSettings::internal_HasKey(MonoString* name)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return settings->hasKey(nativeName);
+	}
+
+	void ScriptEditorSettings::internal_DeleteKey(MonoString* name)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->deleteKey(nativeName);
+	}
+
+	void ScriptEditorSettings::internal_DeleteAllKeys()
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->deleteAllKeys();
+	}
+
 	UINT32 ScriptEditorSettings::internal_GetHash()
 	{
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();

+ 4 - 4
SBansheeEngine/Include/BsScriptComponent.h

@@ -32,11 +32,11 @@ namespace BansheeEngine
 		ScriptComponent(MonoObject* instance);
 		~ScriptComponent() {}
 
-		virtual ScriptObjectBackup beginRefresh();
-		virtual void endRefresh(const ScriptObjectBackup& backupData);
-		virtual MonoObject* _createManagedInstance(bool construct);
+		virtual ScriptObjectBackup beginRefresh() override;
+		virtual void endRefresh(const ScriptObjectBackup& backupData) override;
+		virtual MonoObject* _createManagedInstance(bool construct) override;
 
-		void _onManagedInstanceDeleted();
+		void _onManagedInstanceDeleted() override;
 
 		GameObjectHandle<ManagedComponent> mManagedComponent;
 		String mNamespace;

+ 27 - 0
SBansheeEngine/Include/BsScriptProfilerOverlayInternal.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsProfilerOverlay.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptProfilerOverlayInternal : public ScriptObject < ScriptProfilerOverlayInternal >
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ProfilerOverlayInternal")
+
+		ProfilerOverlayInternal* getInternal() const { return mProfilerOverlayInternal; }
+
+	private:
+		ScriptProfilerOverlayInternal(MonoObject* managedInstance, const SPtr<CameraHandler>& camera);
+		~ScriptProfilerOverlayInternal();
+
+		static void internal_CreateInstance(MonoObject* instance, ScriptCameraHandler* camera);
+		static void internal_SetType(ScriptProfilerOverlayInternal* thisPtr, ProfilerOverlayType type);
+		static void internal_Update(ScriptProfilerOverlayInternal* thisPtr);
+		static void internal_DestroyInstance(ScriptProfilerOverlayInternal* thisPtr);
+
+		ProfilerOverlayInternal* mProfilerOverlayInternal;
+	};
+}

+ 1 - 1
SBansheeEngine/Include/BsScriptTime.h

@@ -13,7 +13,7 @@ namespace BansheeEngine
 	private:
 		static float internal_getElapsed();
 		static float internal_getFrameDelta();
-		static UINT32 internal_getFrameNumber();
+		static UINT64 internal_getFrameNumber();
 		static UINT64 internal_getPrecise();
 
 		ScriptTime(MonoObject* instance);

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -299,6 +299,7 @@
     <ClInclude Include="Include\BsScriptPixelUtility.h" />
     <ClInclude Include="Include\BsScriptPlainText.h" />
     <ClInclude Include="Include\BsScriptPrefab.h" />
+    <ClInclude Include="Include\BsScriptProfilerOverlayInternal.h" />
     <ClInclude Include="Include\BsScriptRenderableHandler.h" />
     <ClInclude Include="Include\BsScriptRenderTarget.h" />
     <ClInclude Include="Include\BsScriptRenderTexture.h" />
@@ -385,6 +386,7 @@
     <ClCompile Include="Source\BsScriptPixelUtility.cpp" />
     <ClCompile Include="Source\BsScriptPlainText.cpp" />
     <ClCompile Include="Source\BsScriptPrefab.cpp" />
+    <ClCompile Include="Source\BsScriptProfilerOverlayInternal.cpp" />
     <ClCompile Include="Source\BsScriptRenderableHandler.cpp" />
     <ClCompile Include="Source\BsScriptRenderTarget.cpp" />
     <ClCompile Include="Source\BsScriptRenderTexture.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -327,6 +327,9 @@
     <ClInclude Include="Include\BsScriptLightInternal.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptProfilerOverlayInternal.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -590,5 +593,8 @@
     <ClCompile Include="Source\BsScriptLightInternal.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptProfilerOverlayInternal.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 63 - 0
SBansheeEngine/Source/BsScriptProfilerOverlayInternal.cpp

@@ -0,0 +1,63 @@
+#include "BsScriptProfilerOverlayInternal.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsApplication.h"
+#include "BsCameraHandler.h"
+#include "BsScriptCameraHandler.h"
+
+namespace BansheeEngine
+{
+	ScriptProfilerOverlayInternal::ScriptProfilerOverlayInternal(MonoObject* managedInstance, const SPtr<CameraHandler>& camera)
+		:ScriptObject(managedInstance), mProfilerOverlayInternal(nullptr)
+	{
+		if (camera != nullptr)
+			mProfilerOverlayInternal = bs_new<ProfilerOverlayInternal>(camera->getViewport());
+	}
+
+	ScriptProfilerOverlayInternal::~ScriptProfilerOverlayInternal()
+	{
+		if (mProfilerOverlayInternal != nullptr)
+			bs_delete(mProfilerOverlayInternal);
+	}
+
+	void ScriptProfilerOverlayInternal::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptProfilerOverlayInternal::internal_CreateInstance);
+		metaData.scriptClass->addInternalCall("Internal_SetType", &ScriptProfilerOverlayInternal::internal_SetType);
+		metaData.scriptClass->addInternalCall("Internal_Update", &ScriptProfilerOverlayInternal::internal_Update);
+		metaData.scriptClass->addInternalCall("Internal_DestroyInstance", &ScriptProfilerOverlayInternal::internal_DestroyInstance);
+	}
+
+	void ScriptProfilerOverlayInternal::internal_CreateInstance(MonoObject* instance, ScriptCameraHandler* camera)
+	{
+		SPtr<CameraHandler> cameraHandler;
+		if (camera != nullptr)
+			cameraHandler = camera->getInternal();
+
+		ScriptProfilerOverlayInternal* nativeInstance = new (bs_alloc<ScriptProfilerOverlayInternal>()) ScriptProfilerOverlayInternal(instance, cameraHandler);
+	}
+
+	void ScriptProfilerOverlayInternal::internal_SetType(ScriptProfilerOverlayInternal* thisPtr, ProfilerOverlayType type)
+	{
+		if (thisPtr->mProfilerOverlayInternal != nullptr)
+			thisPtr->mProfilerOverlayInternal->show(type);
+	}
+
+	void ScriptProfilerOverlayInternal::internal_Update(ScriptProfilerOverlayInternal* thisPtr)
+	{
+		if (thisPtr->mProfilerOverlayInternal != nullptr)
+			thisPtr->mProfilerOverlayInternal->update();
+	}
+
+	void ScriptProfilerOverlayInternal::internal_DestroyInstance(ScriptProfilerOverlayInternal* thisPtr)
+	{
+		if (thisPtr->mProfilerOverlayInternal != nullptr)
+		{
+			bs_delete(thisPtr->mProfilerOverlayInternal);
+			thisPtr->mProfilerOverlayInternal = nullptr;
+		}
+	}
+}

+ 2 - 2
SBansheeEngine/Source/BsScriptTime.cpp

@@ -29,9 +29,9 @@ namespace BansheeEngine
 		return gTime().getFrameDelta();
 	}
 
-	UINT32 ScriptTime::internal_getFrameNumber()
+	UINT64 ScriptTime::internal_getFrameNumber()
 	{
-		return gTime().getFrameNumber();
+		return gTime().getFrameIdx();
 	}
 
 	UINT64 ScriptTime::internal_getPrecise()