浏览代码

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

Marko Pintera 10 年之前
父节点
当前提交
ddef406ac9
共有 34 个文件被更改,包括 749 次插入85 次删除
  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()