Marko Pintera 11 лет назад
Родитель
Сommit
f7b6d5e620
38 измененных файлов с 1899 добавлено и 88 удалено
  1. 2 0
      BansheeEditor/BansheeEditor.vcxproj
  2. 6 0
      BansheeEditor/BansheeEditor.vcxproj.filters
  3. 132 0
      BansheeEditor/Include/BsGizmoManager.h
  4. 457 0
      BansheeEditor/Source/BsGizmoManager.cpp
  5. 76 0
      BansheeEngine/Include/BsCamera.h
  6. 2 2
      BansheeEngine/Include/BsDrawHelper2D.h
  7. 44 2
      BansheeEngine/Include/BsDrawHelper3D.h
  8. 5 19
      BansheeEngine/Include/BsDrawHelperTemplate.h
  9. 105 0
      BansheeEngine/Source/BsCamera.cpp
  10. 18 7
      BansheeEngine/Source/BsDrawHelper2D.cpp
  11. 72 16
      BansheeEngine/Source/BsDrawHelper3D.cpp
  12. 5 0
      BansheeMono/Include/BsMonoAssembly.h
  13. 13 3
      BansheeMono/Include/BsMonoClass.h
  14. 1 1
      BansheeMono/Include/BsMonoField.h
  15. 36 4
      BansheeMono/Include/BsMonoMethod.h
  16. 30 3
      BansheeMono/Source/BsMonoClass.cpp
  17. 103 11
      BansheeMono/Source/BsMonoMethod.cpp
  18. 2 0
      MBansheeEditor/MBansheeEditor.csproj
  19. 23 0
      MBansheeEditor/Scene/DrawGizmo.cs
  20. 85 0
      MBansheeEditor/Scene/Gizmos.cs
  21. 2 0
      MBansheeEngine/MBansheeEngine.csproj
  22. 132 0
      MBansheeEngine/Math/Degree.cs
  23. 6 6
      MBansheeEngine/Math/Matrix3.cs
  24. 10 13
      MBansheeEngine/Math/Quaternion.cs
  25. 132 0
      MBansheeEngine/Math/Radian.cs
  26. 1 0
      SBansheeEditor/Include/BsEditorScriptManager.h
  27. 47 0
      SBansheeEditor/Include/BsScriptGizmoManager.h
  28. 28 0
      SBansheeEditor/Include/BsScriptGizmos.h
  29. 4 0
      SBansheeEditor/SBansheeEditor.vcxproj
  30. 12 0
      SBansheeEditor/SBansheeEditor.vcxproj.filters
  31. 10 0
      SBansheeEditor/Source/BsEditorScriptManager.cpp
  32. 1 1
      SBansheeEditor/Source/BsScriptEditorPlugin.cpp
  33. 205 0
      SBansheeEditor/Source/BsScriptGizmoManager.cpp
  34. 71 0
      SBansheeEditor/Source/BsScriptGizmos.cpp
  35. 4 0
      SBansheeEngine/Include/BsRuntimeScriptObjects.h
  36. 1 0
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  37. 11 0
      SBansheeEngine/Source/BsRuntimeScriptObjects.cpp
  38. 5 0
      SceneView.txt

+ 2 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -278,6 +278,7 @@
     <ClInclude Include="Include\BsEditorWidgetLayout.h" />
     <ClInclude Include="Include\BsEditorWidgetLayoutRTTI.h" />
     <ClInclude Include="Include\BsEditorWidgetManager.h" />
+    <ClInclude Include="Include\BsGizmoManager.h" />
     <ClInclude Include="Include\BsGUIColor.h" />
     <ClInclude Include="Include\BsGUIColorField.h" />
     <ClInclude Include="Include\BsGUIFieldBase.h" />
@@ -340,6 +341,7 @@
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />
     <ClCompile Include="Source\BsEditorWindowManager.cpp" />
+    <ClCompile Include="Source\BsGizmoManager.cpp" />
     <ClCompile Include="Source\BsGUIColor.cpp" />
     <ClCompile Include="Source\BsGUIColorField.cpp" />
     <ClCompile Include="Source\BsGUIDockSlider.cpp" />

+ 6 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -213,6 +213,9 @@
     <ClInclude Include="Include\BsScenePicking.h">
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGizmoManager.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp">
@@ -374,5 +377,8 @@
     <ClCompile Include="Source\BsScenePicking.cpp">
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGizmoManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 132 - 0
BansheeEditor/Include/BsGizmoManager.h

@@ -0,0 +1,132 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsModule.h"
+#include "BsColor.h"
+#include "BsVector2I.h"
+#include "BsMatrix4.h"
+
+namespace BansheeEngine
+{
+	class BS_ED_EXPORT GizmoManager : public Module<GizmoManager>
+	{
+	public:
+		GizmoManager(const HCamera& camera);
+		~GizmoManager();
+
+		void startGizmo(const HSceneObject& gizmoParent);
+		void endGizmo();
+
+		void setColor(const Color& color);
+		void setTransform(const Matrix4& transform);
+		void setPickable(bool pickable) { mPickable = pickable; }
+
+		void drawCube(const Vector3& position, const Vector3& extents);
+		void drawSphere(const Vector3& position, float radius);
+		void drawWireCube(const Vector3& position, const Vector3& extents);
+		void drawWireSphere(const Vector3& position, float radius);
+		void drawLine(const Vector3& start, const Vector3& end);
+		void drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far);
+		void drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale);
+
+		void update();
+		void clearGizmos();
+
+	private:
+		struct CommonData
+		{
+			Color color;
+			Matrix4 transform;
+			HSceneObject sceneObject;
+			bool pickable;
+		};
+
+		struct CubeData : public CommonData
+		{
+			Vector3 position;
+			Vector3 extents;
+		};
+
+		struct SphereData : public CommonData
+		{
+			Vector3 position;
+			float radius;
+		};
+
+		struct LineData : public CommonData
+		{
+			Vector3 start;
+			Vector3 end;
+		};
+
+		struct FrustumData : public CommonData
+		{
+			Vector3 position;
+			float aspect;
+			Degree FOV;
+			float near;
+			float far;
+		};
+
+		struct IconData : public CommonData
+		{
+			Vector3 position;
+			bool fixedScale;
+			HSpriteTexture texture;
+		};
+
+		void buildSolidMesh();
+		void buildWireMesh();
+		void buildIconMesh();
+
+		static const UINT32 VERTEX_BUFFER_GROWTH;
+		static const UINT32 INDEX_BUFFER_GROWTH;
+		static const UINT32 SPHERE_QUALITY;
+		static const float MAX_ICON_RANGE;
+
+		typedef Set<IconData, std::function<bool(const IconData&, const IconData&)>> IconSet;
+
+		HCamera mCamera;
+
+		Color mColor;
+		Matrix4 mTransform;
+		HSceneObject mActiveSO;
+		bool mPickable;
+
+		Vector<CubeData> mSolidCubeData;
+		Vector<CubeData> mWireCubeData;
+		Vector<SphereData> mSolidSphereData;
+		Vector<SphereData> mWireSphereData;
+		Vector<LineData> mLineData;
+		Vector<FrustumData> mFrustumData;
+		Vector<IconData> mIconData;
+
+		UINT32 mTotalRequiredSolidVertices;
+		UINT32 mTotalRequiredSolidIndices;
+
+		UINT32 mTotalRequiredWireVertices;
+		UINT32 mTotalRequiredWireIndices;
+
+		MeshHeapPtr mSolidMeshHeap;
+		MeshHeapPtr mWireMeshHeap;
+		MeshHeapPtr mIconMeshHeap;
+
+		TransientMeshPtr mSolidMesh;
+		TransientMeshPtr mWireMesh;
+		TransientMeshPtr mIconMesh;
+
+		VertexDataDescPtr mSolidVertexDesc;
+		VertexDataDescPtr mWireVertexDesc;
+		VertexDataDescPtr mIconVertexDesc;
+
+		// Transient
+		struct SortedIconData
+		{
+			float distance;
+			Vector2I screenPosition;
+			UINT32 iconIdx;
+		};
+
+		Vector<SortedIconData> mSortedIconData;
+	};
+}

+ 457 - 0
BansheeEditor/Source/BsGizmoManager.cpp

@@ -0,0 +1,457 @@
+#include "BsGizmoManager.h"
+#include "BsMesh.h"
+#include "BsAABox.h"
+#include "BsSphere.h"
+#include "BsVertexDataDesc.h"
+#include "BsDrawHelper3D.h"
+#include "BsMeshHeap.h"
+#include "BsCamera.h"
+#include "BsSpriteTexture.h"
+
+namespace BansheeEngine
+{
+	const UINT32 GizmoManager::VERTEX_BUFFER_GROWTH = 4096;
+	const UINT32 GizmoManager::INDEX_BUFFER_GROWTH = 4096 * 2;
+	const UINT32 GizmoManager::SPHERE_QUALITY = 1;
+	const float GizmoManager::MAX_ICON_RANGE = 500.0f;
+
+	GizmoManager::GizmoManager(const HCamera& camera)
+		:mTotalRequiredSolidIndices(0), mTotalRequiredSolidVertices(0),
+		mTotalRequiredWireVertices(0), mTotalRequiredWireIndices(0), mCamera(camera), mPickable(false)
+	{
+		mSolidVertexDesc = bs_shared_ptr<VertexDataDesc>();
+		mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+		mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL);
+		mSolidVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
+
+		mWireVertexDesc = bs_shared_ptr<VertexDataDesc>();
+		mWireVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+		mWireVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
+
+		mIconVertexDesc = bs_shared_ptr<VertexDataDesc>();
+		mIconVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+		mIconVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
+		mIconVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
+
+		mSolidMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mSolidVertexDesc);
+		mWireMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mWireVertexDesc);
+		mIconMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mIconVertexDesc);
+	}
+
+	GizmoManager::~GizmoManager()
+	{
+		if (mSolidMesh != nullptr)
+			mSolidMeshHeap->dealloc(mSolidMesh);
+
+		if (mWireMesh != nullptr)
+			mWireMeshHeap->dealloc(mWireMesh);
+
+		if (mIconMesh != nullptr)
+			mIconMeshHeap->dealloc(mIconMesh);
+	}
+
+	void GizmoManager::startGizmo(const HSceneObject& gizmoParent)
+	{
+		mActiveSO = gizmoParent;
+	}
+
+	void GizmoManager::endGizmo()
+	{
+		mActiveSO = nullptr;
+	}
+
+	void GizmoManager::setColor(const Color& color)
+	{
+		mColor = color;
+	}
+
+	void GizmoManager::setTransform(const Matrix4& transform)
+	{
+		mTransform = transform;
+	}
+
+	void GizmoManager::drawCube(const Vector3& position, const Vector3& extents)
+	{
+		mSolidCubeData.push_back(CubeData());
+		CubeData& cubeData = mSolidCubeData.back();
+
+		cubeData.position = position;
+		cubeData.extents = extents;
+		cubeData.color = mColor;
+		cubeData.transform = mTransform;
+		cubeData.sceneObject = mActiveSO;
+		cubeData.pickable = mPickable;
+
+		mTotalRequiredSolidVertices += 24;
+		mTotalRequiredSolidIndices += 36;
+	}
+
+	void GizmoManager::drawSphere(const Vector3& position, float radius)
+	{
+		mSolidSphereData.push_back(SphereData());
+		SphereData& sphereData = mSolidSphereData.back();
+
+		sphereData.position = position;
+		sphereData.radius = radius;
+		sphereData.color = mColor;
+		sphereData.transform = mTransform;
+		sphereData.sceneObject = mActiveSO;
+		sphereData.pickable = mPickable;
+
+		UINT32 numVertices, numIndices;
+		DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numVertices, numIndices);
+
+		mTotalRequiredSolidVertices += numVertices;
+		mTotalRequiredSolidIndices += numIndices;
+	}
+
+	void GizmoManager::drawWireCube(const Vector3& position, const Vector3& extents)
+	{
+		mWireCubeData.push_back(CubeData());
+		CubeData& cubeData = mWireCubeData.back();
+
+		cubeData.position = position;
+		cubeData.extents = extents;
+		cubeData.color = mColor;
+		cubeData.transform = mTransform;
+		cubeData.sceneObject = mActiveSO;
+		cubeData.pickable = mPickable;
+
+		mTotalRequiredWireVertices += 8;
+		mTotalRequiredWireIndices += 24;
+	}
+
+	void GizmoManager::drawWireSphere(const Vector3& position, float radius)
+	{
+		mWireSphereData.push_back(SphereData());
+		SphereData& sphereData = mWireSphereData.back();
+
+		sphereData.position = position;
+		sphereData.radius = radius;
+		sphereData.color = mColor;
+		sphereData.transform = mTransform;
+		sphereData.sceneObject = mActiveSO;
+		sphereData.pickable = mPickable;
+
+		UINT32 numVertices, numIndices;
+		DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numVertices, numIndices);
+
+		mTotalRequiredWireVertices += numVertices;
+		mTotalRequiredWireIndices += numIndices;
+	}
+
+	void GizmoManager::drawLine(const Vector3& start, const Vector3& end)
+	{
+		mLineData.push_back(LineData());
+		LineData& lineData = mLineData.back();
+
+		lineData.start = start;
+		lineData.end = end;
+		lineData.color = mColor;
+		lineData.transform = mTransform;
+		lineData.sceneObject = mActiveSO;
+		lineData.pickable = mPickable;
+
+		mTotalRequiredWireVertices += 2;
+		mTotalRequiredWireIndices += 2;
+	}
+
+	void GizmoManager::drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far)
+	{
+		mFrustumData.push_back(FrustumData());
+		FrustumData& frustumData = mFrustumData.back();
+
+		frustumData.position = position;
+		frustumData.aspect = aspect;
+		frustumData.FOV = FOV;
+		frustumData.near = near;
+		frustumData.far = far;
+		frustumData.color = mColor;
+		frustumData.transform = mTransform;
+		frustumData.sceneObject = mActiveSO;
+		frustumData.pickable = mPickable;
+
+		mTotalRequiredWireVertices += 8;
+		mTotalRequiredWireIndices += 36;
+	}
+
+	void GizmoManager::drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale)
+	{
+		mIconData.push_back(IconData());
+		IconData& iconData = mIconData.back();
+
+		iconData.position = position;
+		iconData.texture = image;
+		iconData.fixedScale = fixedScale;
+		iconData.color = mColor;
+		iconData.transform = mTransform;
+		iconData.sceneObject = mActiveSO;
+		iconData.pickable = mPickable;
+	}
+
+	void GizmoManager::update()
+	{
+		buildSolidMesh();
+		buildWireMesh();
+		buildIconMesh();
+	}
+
+	void GizmoManager::clearGizmos()
+	{
+		mSolidCubeData.clear();
+		mWireCubeData.clear();
+		mSolidSphereData.clear();
+		mWireSphereData.clear();
+		mLineData.clear();
+		mFrustumData.clear();
+		mIconData.clear();
+
+		mTotalRequiredSolidVertices = 0;
+		mTotalRequiredSolidIndices = 0;
+		mTotalRequiredWireVertices = 0;
+		mTotalRequiredWireIndices = 0;
+	}
+
+	void GizmoManager::buildSolidMesh()
+	{
+		MeshDataPtr meshData = bs_shared_ptr<MeshData>(mTotalRequiredSolidVertices, mTotalRequiredSolidIndices, mSolidVertexDesc);
+
+		UINT32 curVertexOffset = 0;
+		UINT32 curIndexOffet = 0;
+
+		auto positionIter = meshData->getVec3DataIter(VES_POSITION);
+		auto normalIter = meshData->getVec3DataIter(VES_NORMAL);
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+
+		for (auto& cubeData : mSolidCubeData)
+		{
+			AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
+			DrawHelper3D::instance().solidAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
+
+			Matrix4 transformIT = cubeData.transform.inverseAffine().transpose();
+			RGBA color = cubeData.color.getAsRGBA();
+
+			UINT32 numVertices = 24;
+			for (UINT32 i = 0; i < numVertices; i++)
+			{
+				Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
+				Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
+				
+				positionIter.addValue(worldPos);
+				normalIter.addValue(worldNormal);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += numVertices;
+			curIndexOffet += 36;
+		}
+
+		UINT32 numSphereVertices, numSphereIndices;
+		DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
+
+		for (auto& sphereData : mSolidSphereData)
+		{
+			Sphere sphere(sphereData.position, sphereData.radius);
+			DrawHelper3D::instance().solidSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
+
+			Matrix4 transformIT = sphereData.transform.inverseAffine().transpose();
+			RGBA color = sphereData.color.getAsRGBA();
+
+			for (UINT32 i = 0; i < numSphereVertices; i++)
+			{
+				Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
+				Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
+
+				positionIter.addValue(worldPos);
+				normalIter.addValue(worldNormal);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += numSphereVertices;
+			curIndexOffet += numSphereIndices;
+		}
+
+		if (mSolidMesh != nullptr)
+			mSolidMeshHeap->dealloc(mSolidMesh);
+
+		mSolidMesh = mSolidMeshHeap->alloc(meshData, DOT_TRIANGLE_LIST);
+	}
+
+	void GizmoManager::buildWireMesh()
+	{
+		MeshDataPtr meshData = bs_shared_ptr<MeshData>(mTotalRequiredWireVertices, mTotalRequiredWireIndices, mWireVertexDesc);
+
+		UINT32 curVertexOffset = 0;
+		UINT32 curIndexOffet = 0;
+
+		auto positionIter = meshData->getVec3DataIter(VES_POSITION);
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+
+		for (auto& cubeData : mWireCubeData)
+		{
+			AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
+			DrawHelper3D::instance().wireAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
+
+			RGBA color = cubeData.color.getAsRGBA();
+
+			UINT32 numVertices = 8;
+			for (UINT32 i = 0; i < numVertices; i++)
+			{
+				Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
+
+				positionIter.addValue(worldPos);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += numVertices;
+			curIndexOffet += 24;
+		}
+
+		UINT32 numSphereVertices, numSphereIndices;
+		DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
+
+		for (auto& sphereData : mWireSphereData)
+		{
+			Sphere sphere(sphereData.position, sphereData.radius);
+			DrawHelper3D::instance().wireSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
+
+			RGBA color = sphereData.color.getAsRGBA();
+			for (UINT32 i = 0; i < numSphereVertices; i++)
+			{
+				Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
+
+				positionIter.addValue(worldPos);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += numSphereVertices;
+			curIndexOffet += numSphereIndices;
+		}
+
+		for (auto& lineData : mLineData)
+		{
+			DrawHelper3D::instance().pixelLine(lineData.start, lineData.end, meshData, curVertexOffset, curIndexOffet);
+
+			RGBA color = lineData.color.getAsRGBA();
+			for (UINT32 i = 0; i < 2; i++)
+			{
+				Vector3 worldPos = lineData.transform.multiply3x4(positionIter.getValue());
+
+				positionIter.addValue(worldPos);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += 2;
+			curIndexOffet += 2;
+		}
+
+		for (auto& frustumData : mFrustumData)
+		{
+			DrawHelper3D::instance().wireFrustum(frustumData.aspect, frustumData.FOV, frustumData.near, 
+				frustumData.far, meshData, curVertexOffset, curIndexOffet);
+
+			RGBA color = frustumData.color.getAsRGBA();
+			for (UINT32 i = 0; i < 8; i++)
+			{
+				Vector3 worldPos = frustumData.transform.multiply3x4(positionIter.getValue());
+
+				positionIter.addValue(worldPos);
+				colorIter.addValue(color);
+			}
+
+			curVertexOffset += 8;
+			curIndexOffet += 24;
+		}
+
+		if (mWireMesh != nullptr)
+			mWireMeshHeap->dealloc(mWireMesh);
+
+		mWireMesh = mWireMeshHeap->alloc(meshData, DOT_LINE_LIST);
+	}
+
+	void GizmoManager::buildIconMesh()
+	{
+		mSortedIconData.clear();
+		
+		if (mIconData.size() > mSortedIconData.size())
+			mSortedIconData.resize(mIconData.size());
+
+		UINT32 i = 0;
+		for (auto& iconData : mIconData)
+		{
+			Vector3 viewPoint = mCamera->worldToViewPoint(iconData.position);
+
+			float distance = -viewPoint.z;
+			if (distance < mCamera->getNearClipDistance()) // Ignore behind clip plane
+				continue;
+
+			if (distance > MAX_ICON_RANGE) // Ignore too far away
+				continue;
+
+			if (!iconData.texture) // Ignore missing texture
+				continue;
+
+			SortedIconData& sortedIconData = mSortedIconData[i];
+			sortedIconData.iconIdx = i;
+			sortedIconData.distance = distance;
+			sortedIconData.screenPosition = mCamera->viewToScreenPoint(viewPoint);
+
+			i++;
+		}
+
+		UINT32 actualNumIcons = i;
+
+		// Sort back to front first, then by texture
+		std::sort(mSortedIconData.begin(), mSortedIconData.begin() + actualNumIcons, 
+			[&](const SortedIconData& a, const SortedIconData& b)
+		{
+			if (a.distance == b.distance)
+			{
+				HSpriteTexture texA = mIconData[a.iconIdx].texture;
+				HSpriteTexture texB = mIconData[b.iconIdx].texture;
+
+				if (texA == texB)
+					return a.iconIdx < b.iconIdx;
+
+				return texA->getInternalID() < texB->getInternalID();
+			}
+			else
+				return a.distance > b.distance;
+		});
+
+		for (i = 0; i < actualNumIcons; i++)
+		{
+
+		}
+
+		// TODO - Group by texture
+		// TODO - Scale icons to always fit in some max size
+		// TODO - Render in screen space
+
+
+		// TODO - Set up a render method that actually renders the gizmos
+		//	      - Optionally also add a special method that renders the gizmos for picking purposes
+
+
+		// ----------------------------
+		// TODO - In SBansheeEditor:
+		//  - Add BsScriptGizmos that implements the C# Gizmos interface
+		//  - It tracks when an assembly is reloaded, and finds all valid gizmo drawing methods
+		//     - They need to have DrawGizmo attribute and accept a Component of a specific type as first param (and be static)
+		//     - Internally they call GizmoManager
+		//  - Then in update:
+		//   - Call GizmoManager and clear gizmos
+		//   - Go through every SceneObject and their components to find custom gizmos for those types
+		//   - Call their draw gizmo methods
+		//
+		// TODO - In ScenePicking:
+		//  - Call GizmoManager that renders all gizmos using picking color coding
+		//   - I might instead just add a way to retrieve render data from GizmoManager since GizmoManager doesn't have access to picking materials
+		//
+		// TODO - How do I handle C++ types like Camera and Renderable?
+		//  - Add ComponentBase.cs from which Camera and Renderable inherit
+		//  - Ensure any instances where I currently use Component I use ComponentBase instead (except for actual ManagedComponents)
+		//  - Camera and Renderable will have their own specialized implementation for scripts, but interally I will use normal Camera/Renderable components
+		//  - TODO Haven't thought this out yet
+	}
+}

+ 76 - 0
BansheeEngine/Include/BsCamera.h

@@ -282,6 +282,82 @@ namespace BansheeEngine
 		 */
 		void setLayers(UINT64 layers) { mLayers = layers; markCoreDirty(); }
 
+		/**
+		 * @brief	Converts a point in world space to screen coordinates (in pixels
+		 *			corresponding to the render target attached to the camera).
+		 */
+		Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in world space to normalized clip coordinates 
+		 *			(in [0, 1] range).
+		 */
+		Vector2 worldToClipPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in world space to point relative to camera's
+		 *			coordinate system (view space).
+		 */
+		Vector3 worldToViewPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to a point in world space.
+		 */
+		Vector3 screenToWorldPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to a point relative to
+		 *			camera's coordinate system (view space).
+		 */
+		Vector3 screenToViewPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to normalized clip 
+		 *			coordinates (in [0, 1] range).
+		 */
+		Vector2 screenToClipPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into a point in world space.
+		 */
+		Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into a point in screen space (pixels corresponding to render target 
+		 *			attached to the camera.
+		 */
+		Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into normalized clip coordinates (in [0, 1] range).
+		 */
+		Vector2 viewToClipPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point in world space.
+		 */
+		Vector3 clipToWorldPoint(const Vector2& clipPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point relative to camera's coordinate system (view space).
+		 */
+		Vector3 clipToViewPoint(const Vector2& clipPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point in screen space (pixels corresponding to render target attached 
+		 *			to the camera)
+		 */
+		Vector2I clipToScreenPoint(const Vector2& clipPoint) const;
+
         static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
 
 		/************************************************************************/

+ 2 - 2
BansheeEngine/Include/BsDrawHelper2D.h

@@ -36,7 +36,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	DrawHelperTemplate::pixelLine
 		 */
-		void pixelLine(const Vector2& a, const Vector2& b, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
+		void pixelLine(const Vector2& a, const Vector2& b, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 		/**
 		 * @copydoc	DrawHelperTemplate::antialiasedLine
@@ -46,7 +46,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	DrawHelperTemplate::pixelLineList
 		 */
-		void pixelLineList(const Vector<Vector2>& linePoints, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
+		void pixelLineList(const Vector<Vector2>& linePoints, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 		/**
 		 * @copydoc	DrawHelperTemplate::antialiasedLineList

+ 44 - 2
BansheeEngine/Include/BsDrawHelper3D.h

@@ -240,7 +240,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	DrawHelperTemplate::pixelLine
 		 */
-		void pixelLine(const Vector3& a, const Vector3& b, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
+		void pixelLine(const Vector3& a, const Vector3& b, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 		/**
 		 * @copydoc	DrawHelperTemplate::antialiasedLine
@@ -251,7 +251,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	DrawHelperTemplate::pixelLineList
 		 */
-		void pixelLineList(const Vector<Vector3>& linePoints, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
+		void pixelLineList(const Vector<Vector3>& linePoints, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 		/**
 		 * @copydoc	DrawHelperTemplate::antialiasedLineList
@@ -259,6 +259,48 @@ namespace BansheeEngine
 		void antialiasedLineList(const Vector<Vector3>& linePoints, const Vector3& up, float width, float borderWidth, 
 			const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a solid sphere
+		 *			of the specified quality.
+		 */
+		static void getNumElementsSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a wire sphere
+		 *			of the specified quality.
+		 */
+		static void getNumElementsWireSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a solid arc
+		 *			of the specified quality.
+		 */
+		static void getNumElementsArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a wire arc
+		 *			of the specified quality.
+		 */
+		static void getNumElementsWireArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a solid desc
+		 *			of the specified quality.
+		 */
+		static void getNumElementsDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a wire disc
+		 *			of the specified quality.
+		 */
+		static void getNumElementsWireDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
+		/**
+		 * @brief	Calculates number of vertices and indices required for geometry of a cone
+		 *			of the specified quality.
+		 */
+		static void getNumElementsCone(UINT32 quality, UINT32& numVertices, UINT32& numIndices);
+
 		/**
 		 * @brief	Constructs a one-pixel wide line and draws it in the specified camera. 
 		 *

+ 5 - 19
BansheeEngine/Include/BsDrawHelperTemplate.h

@@ -75,29 +75,26 @@ namespace BansheeEngine
 		 *
 		 * @param	a				Start point of the line.
 		 * @param	b				End point of the line.
-		 * @param	color			Color of the line.
 		 * @param	meshData		Mesh data that will be populated.
 		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
 		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 * 							
 		 * @note	Provided MeshData must have some specific elements at least:
 		 * 			  T		  VES_POSITION
-		 * 			  UINT32  VES_COLOR
 		 * 			  32bit index buffer
 		 * 			  Enough space for 2 vertices and 2 indices
 		 *
 		 *			Primitives are output in the form of a line list.
 		 */
-		void pixelLine(const T& a, const T& b, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+		void pixelLine(const T& a, const T& b, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 		{
 			UINT32* indexData = meshData->getIndices32();
 			UINT8* positionData = meshData->getElementData(VES_POSITION);
-			UINT8* colorData = meshData->getElementData(VES_COLOR);
 
 			assert((vertexOffset + 2) <= meshData->getNumVertices());
 			assert((indexOffset + 2) <= meshData->getNumIndices());
 
-			pixelLine(a, b, color, positionData, colorData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
+			pixelLine(a, b, color, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
 		}
 
 		/**
@@ -137,20 +134,18 @@ namespace BansheeEngine
 		 * @brief	Fills the mesh data with vertices representing per-pixel lines.
 		 *
 		 * @param	linePoints		A list of start and end points for the lines. Must be a multiple of 2.
-		 * @param	color			Color of the line.
 		 * @param	meshData		Mesh data that will be populated.
 		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
 		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 * 							
 		 * @note	Provided MeshData must have some specific elements at least:
 		 * 			  T		  VES_POSITION
-		 * 			  UINT32  VES_COLOR
 		 * 			  32bit index buffer
 		 * 			  Enough space for (numLines * 2) vertices and (numLines * 2) indices
 		 *
 		 *			Primitives are output in the form of a line list.
 		 */
-		void pixelLineList(const typename Vector<T>& linePoints, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+		void pixelLineList(const typename Vector<T>& linePoints, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 		{
 			assert(linePoints.size() % 2 == 0);
 
@@ -162,12 +157,11 @@ namespace BansheeEngine
 
 			UINT32* indexData = meshData->getIndices32();
 			UINT8* positionData = meshData->getElementData(VES_POSITION);
-			UINT8* colorData = meshData->getElementData(VES_COLOR);
 
 			UINT32 numPoints = (UINT32)linePoints.size();
 			for(UINT32 i = 0; i < numPoints; i += 2)
 			{
-				pixelLine(linePoints[i], linePoints[i + 1], color, positionData, colorData, curVertOffset, meshData->getVertexDesc()->getVertexStride(), indexData, curIdxOffset);
+				pixelLine(linePoints[i], linePoints[i + 1], color, positionData, curVertOffset, meshData->getVertexDesc()->getVertexStride(), indexData, curIdxOffset);
 
 				curVertOffset += 2;
 				curIdxOffset += 2;
@@ -224,15 +218,13 @@ namespace BansheeEngine
 		 *
 		 * @param	a				Start point of the line.
 		 * @param	b				End point of the line.
-		 * @param	color			Color of the line.
 		 * @param	outVertices		Output buffer that will store the vertex position data.
-		 * @param	outColors		Output buffer that will store the vertex color data.
 		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
 		 * @param	vertexStride	Size of a single vertex, in bytes. (Same for both position and color buffer)
 		 * @param	outIndices		Output buffer that will store the index data. Indices are 32bit.
 		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 */
-		void pixelLine(const T& a, const T& b, const Color& color, UINT8* outVertices, UINT8* outColors, 
+		void pixelLine(const T& a, const T& b, UINT8* outVertices,  
 			UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
 		{
 			outVertices += (vertexOffset * vertexStride);
@@ -244,12 +236,6 @@ namespace BansheeEngine
 			vertices = (T*)(outVertices + vertexStride);
 			(*vertices) = b;
 
-			UINT32* colors = (UINT32*)outColors;
-			(*colors) = color.getAsRGBA();
-
-			colors = (UINT32*)(outColors + vertexStride);
-			(*colors) = color.getAsRGBA();
-
 			outIndices += indexOffset;
 			outIndices[0] = vertexOffset + 0;
 			outIndices[1] = vertexOffset + 1;

+ 105 - 0
BansheeEngine/Source/BsCamera.cpp

@@ -489,6 +489,111 @@ namespace BansheeEngine
 		mRecalcFrustumPlanes = true;
     }
 
+	Vector2I Camera::worldToScreenPoint(const Vector3& worldPoint) const
+	{
+		Vector2 clipPoint = worldToClipPoint(worldPoint);
+		return clipToScreenPoint(clipPoint);
+	}
+
+	Vector2 Camera::worldToClipPoint(const Vector3& worldPoint) const
+	{
+		Vector3 viewPoint = worldToViewPoint(worldPoint);
+		return viewToClipPoint(viewPoint);
+	}
+
+	Vector3 Camera::worldToViewPoint(const Vector3& worldPoint) const
+	{
+		return getViewMatrix().multiply3x4(worldPoint);
+	}
+
+	Vector3 Camera::screenToWorldPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint = screenToClipPoint(screenPoint);
+		return clipToWorldPoint(clipPoint);
+	}
+
+	Vector3 Camera::screenToViewPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint = screenToClipPoint(screenPoint);
+		return clipToViewPoint(clipPoint);
+	}
+
+	Vector2 Camera::screenToClipPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint;
+		clipPoint.x = (float)(((screenPoint.x - mViewport->getX()) / mViewport->getWidth()) * 2.0f - 1.0f);
+		clipPoint.y = (float)(((screenPoint.y - mViewport->getY()) / mViewport->getHeight()) * 2.0f - 1.0f);
+
+		return clipPoint;
+	}
+
+	Vector3 Camera::viewToWorldPoint(const Vector3& viewPoint) const
+	{
+		return getViewMatrix().inverseAffine().multiply3x4(viewPoint);
+	}
+
+	Vector2I Camera::viewToScreenPoint(const Vector3& viewPoint) const
+	{
+		Vector2 clipPoint = viewToClipPoint(viewPoint);
+		return clipToScreenPoint(clipPoint);
+	}
+
+	Vector2 Camera::viewToClipPoint(const Vector3& viewPoint) const
+	{
+		Vector4 projPoint = getProjectionMatrix().multiply(Vector4(viewPoint.x, viewPoint.y, viewPoint.z, 1.0f));
+
+		if (projPoint.w > 1e-7f)
+		{
+			float invW = 1.0f / projPoint.w;
+			projPoint.x *= invW;
+			projPoint.y *= invW;
+		}
+		else
+		{
+			projPoint.x = 0.0f;
+			projPoint.y = 0.0f;
+		}
+
+		return Vector2(projPoint.x, projPoint.y);
+	}
+
+	Vector3 Camera::clipToWorldPoint(const Vector2& clipPoint) const
+	{
+		Vector2I screenPoint = clipToScreenPoint(clipPoint);
+		return screenToWorldPoint(screenPoint);
+	}
+
+	Vector3 Camera::clipToViewPoint(const Vector2& clipPoint) const
+	{
+		Vector4 unprojPoint(clipPoint.x, clipPoint.y, 0.5f, 1.0f); // 0.5f arbitrary depth
+		unprojPoint = getProjectionMatrix().inverse().multiply(unprojPoint);
+
+		if (unprojPoint.w > 1e-7f)
+		{
+			float invW = 1.0f / unprojPoint.w;
+			unprojPoint.x *= invW;
+			unprojPoint.y *= invW;
+			unprojPoint.z *= invW;
+		}
+		else
+		{
+			unprojPoint.x = 0.0f;
+			unprojPoint.y = 0.0f;
+			unprojPoint.z = 0.0f;
+		}
+
+		return Vector3(unprojPoint.x, unprojPoint.y, unprojPoint.z);
+	}
+
+	Vector2I Camera::clipToScreenPoint(const Vector2& clipPoint) const
+	{
+		Vector2I screenPoint;
+		screenPoint.x = mViewport->getX() + (clipPoint.x + 1.0f) * mViewport->getWidth() * 0.5f;
+		screenPoint.y = mViewport->getY() + (clipPoint.y + 1.0f) * mViewport->getHeight() * 0.5f;
+
+		return screenPoint;
+	}
+
 	CameraProxyPtr Camera::_createProxy() const
 	{
 		CameraProxyPtr proxy = bs_shared_ptr<CameraProxy>();

+ 18 - 7
BansheeEngine/Source/BsDrawHelper2D.cpp

@@ -40,9 +40,9 @@ namespace BansheeEngine
 		pixelSolidPolygon(points, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
 	}
 
-	void DrawHelper2D::pixelLine(const Vector2& a, const Vector2& b, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+	void DrawHelper2D::pixelLine(const Vector2& a, const Vector2& b, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
-		DrawHelperTemplate<Vector2>::pixelLine(a, b, color, meshData, vertexOffset, indexOffset);
+		DrawHelperTemplate<Vector2>::pixelLine(a, b, meshData, vertexOffset, indexOffset);
 	}
 
 	void DrawHelper2D::antialiasedLine(const Vector2& a, const Vector2& b, float width, float borderWidth, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
@@ -50,9 +50,9 @@ namespace BansheeEngine
 		DrawHelperTemplate<Vector2>::antialiasedLine(a, b, Vector2::ZERO, width, borderWidth, color, meshData, vertexOffset, indexOffset);
 	}
 
-	void DrawHelper2D::pixelLineList(const Vector<Vector2>& linePoints, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+	void DrawHelper2D::pixelLineList(const Vector<Vector2>& linePoints, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
-		DrawHelperTemplate<Vector2>::pixelLineList(linePoints, color, meshData, vertexOffset, indexOffset);
+		DrawHelperTemplate<Vector2>::pixelLineList(linePoints, meshData, vertexOffset, indexOffset);
 	}
 
 	void DrawHelper2D::antialiasedLineList(const Vector<Vector2>& linePoints, float width, float borderWidth, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
@@ -134,7 +134,12 @@ namespace BansheeEngine
 			actualB = normalizedCoordToClipSpace(b);
 		}
 
-		pixelLine(actualA, actualB, color, meshData, 0, 0);
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+		RGBA rgba = color.getAsRGBA();
+		colorIter.addValue(rgba);
+		colorIter.addValue(rgba);
+
+		pixelLine(actualA, actualB, meshData, 0, 0);
 
 		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);
 
@@ -206,6 +211,12 @@ namespace BansheeEngine
 		MeshDataPtr meshData = bs_shared_ptr<MeshData, ScratchAlloc>(
 			(UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc);
 
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+		RGBA rgba = color.getAsRGBA();
+
+		for (UINT32 i = 0; i < (UINT32)linePoints.size(); i++)
+			colorIter.addValue(rgba);
+
 		if(coordType == DebugDrawCoordType::Normalized)
 		{
 			Vector<Vector2> points;
@@ -213,11 +224,11 @@ namespace BansheeEngine
 			for(UINT32 i = 0; i < numPoints; i++)
 				points.push_back(normalizedCoordToClipSpace(linePoints[i]));
 
-			pixelLineList(points, color, meshData, 0, 0);
+			pixelLineList(points, meshData, 0, 0);
 		}
 		else
 		{
-			pixelLineList(linePoints, color, meshData, 0, 0);
+			pixelLineList(linePoints, meshData, 0, 0);
 		}		
 
 		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);

+ 72 - 16
BansheeEngine/Source/BsDrawHelper3D.cpp

@@ -57,8 +57,8 @@ namespace BansheeEngine
 		UINT32* indexData = meshData->getIndices32();
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 
-		UINT32 requiredNumVertices = 3 * ((quality + 1) * 4);
-		UINT32 requiredNumIndices = 6 * ((quality + 1) * 4);
+		UINT32 requiredNumVertices, requiredNumIndices;
+		getNumElementsWireSphere(quality, requiredNumVertices, requiredNumIndices);
 
 		assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
 		assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
@@ -82,8 +82,8 @@ namespace BansheeEngine
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* normalData = meshData->getElementData(VES_NORMAL);
 
-		UINT32 requiredNumVertices = 20 * (4 * ((UINT32)std::pow(3, quality)));
-		UINT32 requiredNumIndices = requiredNumVertices;
+		UINT32 requiredNumVertices, requiredNumIndices;
+		getNumElementsSphere(quality, requiredNumVertices, requiredNumIndices);
 
 		assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
 		assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
@@ -110,8 +110,8 @@ namespace BansheeEngine
 		UINT32* indexData = meshData->getIndices32();
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 
-		UINT32 requiredNumVertices = (quality + 1) * 5;
-		UINT32 requiredNumIndices = ((quality + 1) * 5 - 1) * 2;
+		UINT32 requiredNumVertices, requiredNumIndices;
+		getNumElementsWireArc(quality, requiredNumVertices, requiredNumIndices);
 
 		assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
 		assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
@@ -127,8 +127,8 @@ namespace BansheeEngine
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* normalData = meshData->getElementData(VES_NORMAL);
 
-		UINT32 requiredNumVertices = (quality + 1) * 5 + 1;
-		UINT32 requiredNumIndices = ((quality + 1) * 5 - 1) * 3;
+		UINT32 requiredNumVertices, requiredNumIndices;
+		getNumElementsArc(quality, requiredNumVertices, requiredNumIndices);
 
 		assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
 		assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
@@ -156,8 +156,8 @@ namespace BansheeEngine
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* normalData = meshData->getElementData(VES_NORMAL);
 
-		UINT32 requiredNumVertices = ((quality + 1) * 4 + 1) * 2;
-		UINT32 requiredNumIndices = ((quality + 1) * 4 - 1) * 6;
+		UINT32 requiredNumVertices, requiredNumIndices;
+		getNumElementsCone(quality, requiredNumVertices, requiredNumIndices);
 
 		assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
 		assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
@@ -166,9 +166,9 @@ namespace BansheeEngine
 			meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset, quality);
 	}
 
-	void DrawHelper3D::pixelLine(const Vector3& a, const Vector3& b, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+	void DrawHelper3D::pixelLine(const Vector3& a, const Vector3& b, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
-		DrawHelperTemplate<Vector3>::pixelLine(a, b, color, meshData, vertexOffset, indexOffset);
+		DrawHelperTemplate<Vector3>::pixelLine(a, b, meshData, vertexOffset, indexOffset);
 	}
 
 	void DrawHelper3D::antialiasedLine(const Vector3& a, const Vector3& b, const Vector3& up, float width, float borderWidth, 
@@ -177,9 +177,9 @@ namespace BansheeEngine
 		DrawHelperTemplate<Vector3>::antialiasedLine(a, b, up, width, borderWidth, color, meshData, vertexOffset, indexOffset);
 	}
 
-	void DrawHelper3D::pixelLineList(const Vector<Vector3>& linePoints, const Color& color, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
+	void DrawHelper3D::pixelLineList(const Vector<Vector3>& linePoints, const MeshDataPtr& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
-		DrawHelperTemplate<Vector3>::pixelLineList(linePoints, color, meshData, vertexOffset, indexOffset);
+		DrawHelperTemplate<Vector3>::pixelLineList(linePoints, meshData, vertexOffset, indexOffset);
 	}
 
 	void DrawHelper3D::antialiasedLineList(const Vector<Vector3>& linePoints, const Vector3& up, float width, float borderWidth, 
@@ -188,6 +188,50 @@ namespace BansheeEngine
 		DrawHelperTemplate<Vector3>::antialiasedLineList(linePoints, up, width, borderWidth, color, meshData, vertexOffset, indexOffset);
 	}
 
+	/************************************************************************/
+	/* 								ELEMENT COUNT                      		*/
+	/************************************************************************/
+
+	void DrawHelper3D::getNumElementsSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		numVertices = 20 * (4 * ((UINT32)std::pow(3, quality)));
+		numIndices = numVertices;
+	}
+
+	void DrawHelper3D::getNumElementsWireSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		numVertices = 3 * ((quality + 1) * 4);
+		numIndices = 6 * ((quality + 1) * 4);
+	}
+
+	void DrawHelper3D::getNumElementsArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		numVertices = (quality + 1) * 5 + 1;
+		numIndices = ((quality + 1) * 5 - 1) * 3;
+	}
+
+	void DrawHelper3D::getNumElementsWireArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		numVertices = (quality + 1) * 5;
+		numIndices = ((quality + 1) * 5 - 1) * 2;
+	}
+
+	void DrawHelper3D::getNumElementsDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		getNumElementsArc(quality, numVertices, numIndices);
+	}
+
+	void DrawHelper3D::getNumElementsWireDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		getNumElementsWireArc(quality, numVertices, numIndices);
+	}
+
+	void DrawHelper3D::getNumElementsCone(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
+	{
+		numVertices = ((quality + 1) * 4 + 1) * 2;
+		numIndices = ((quality + 1) * 4 - 1) * 6;
+	}
+
 	/************************************************************************/
 	/* 								DRAW	                     			*/
 	/************************************************************************/
@@ -204,7 +248,13 @@ namespace BansheeEngine
 
 		MeshDataPtr meshData = bs_shared_ptr<MeshData, ScratchAlloc>(2, 2, mVertexDesc);
 
-		pixelLine(a, b, color, meshData, 0, 0);
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+		RGBA rgba = color.getAsRGBA();
+
+		colorIter.addValue(rgba);
+		colorIter.addValue(rgba);
+
+		pixelLine(a, b, meshData, 0, 0);
 
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());
@@ -253,7 +303,13 @@ namespace BansheeEngine
 		MeshDataPtr meshData = bs_shared_ptr<MeshData, ScratchAlloc>(
 			(UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc);
 
-		pixelLineList(linePoints, color, meshData, 0, 0);
+		auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
+		RGBA rgba = color.getAsRGBA();
+
+		for (UINT32 i = 0; i < (UINT32)linePoints.size(); i++)
+			colorIter.addValue(rgba);
+
+		pixelLineList(linePoints, meshData, 0, 0);
 
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());

+ 5 - 0
BansheeMono/Include/BsMonoAssembly.h

@@ -39,6 +39,11 @@ namespace BansheeEngine
 	public:
 		virtual ~MonoAssembly();
 
+		/**
+		 * @brief	Returns the name of this assembly.
+		 */
+		const String& getName() const { return mName; }
+
 		/**
 	     * @brief	Attempts to find a managed class with the specified namespace and name
 		 *			in this assembly. Returns null if one cannot be found.

+ 13 - 3
BansheeMono/Include/BsMonoClass.h

@@ -56,7 +56,7 @@ namespace BansheeEngine
 		 *			if method cannot be found.
 		 *			Does not query base class methods.
 		 */
-		MonoMethod& getMethod(const String& name, UINT32 numParams = 0);
+		MonoMethod& getMethod(const String& name, UINT32 numParams = 0) const;
 
 		/**
 		 * @brief	Returns an object referencing a field with the specified name.
@@ -89,7 +89,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Example: name = "CreateInstance", signature = "Vector2,int[]"
 		 */
-		MonoMethod* getMethodExact(const String& name, const String& signature);
+		MonoMethod* getMethodExact(const String& name, const String& signature) const;
 
 		/**
 		 * @brief	Returns all fields belonging to this class.
@@ -98,6 +98,13 @@ namespace BansheeEngine
 		 */
 		const Vector<MonoField*> getAllFields() const;
 
+		/**
+		 * @brief	Returns all methods belonging to this class.
+		 *
+		 * @note	Be aware this will not include the methods of any base classes.
+		 */
+		const Vector<MonoMethod*> getAllMethods() const;
+
 		/**
 		 * @brief	Check if this class has an attribute of the type "monoClass".
 		 */
@@ -192,11 +199,14 @@ namespace BansheeEngine
 		String mTypeName;
 		String mFullName;
 
-		UnorderedMap<MethodId, MonoMethod*, MethodId::Hash, MethodId::Equals> mMethods; 
+		mutable UnorderedMap<MethodId, MonoMethod*, MethodId::Hash, MethodId::Equals> mMethods; 
 		mutable UnorderedMap<String, MonoField*> mFields; 
 		UnorderedMap<String, MonoProperty*> mProperties;
 
 		mutable bool mHasCachedFields;
 		mutable Vector<MonoField*> mCachedFieldList;
+
+		mutable bool mHasCachedMethods;
+		mutable Vector<MonoMethod*> mCachedMethodList;
 	};
 }

+ 1 - 1
BansheeMono/Include/BsMonoField.h

@@ -62,7 +62,7 @@ namespace BansheeEngine
 		void setValue(MonoObject* instance, void* value);
 
 		/**
-		 * @brief	Checks if field has an attribute if the specified type.
+		 * @brief	Checks if field has an attribute of the specified type.
 		 */
 		bool hasAttribute(MonoClass* monoClass);
 

+ 36 - 4
BansheeMono/Include/BsMonoMethod.h

@@ -14,7 +14,6 @@ namespace BansheeEngine
 	class BS_MONO_EXPORT MonoMethod
 	{
 	public:
-		
 		/**
 		 * @brief	Invokes the method on the provided object instance. 
 		 *			This does not respect polymorphism and will invoke the exact method
@@ -56,21 +55,54 @@ namespace BansheeEngine
 		 */
 		String getName() const;
 
-
 		/**
 		 * @brief	Returns the type of the return value. Returns null if method
 		 *			has no return value.
 		 */
-		MonoClass* getReturnType();
+		MonoClass* getReturnType() const;
+
+		/**
+		 * @brief	Returns the number of parameters the method expects.
+		 */
+		UINT32 getNumParameters() const;
+
+		/**
+		 * @brief	Returns the type of the method parameter at the specified index.
+		 */
+		MonoClass* getParameterType(UINT32 paramIdx) const;
+
+		/**
+		 * @brief	Returns true if the method doesn't require a class instance.
+		 */
+		bool isStatic() const;
+
+		/**
+		 * @brief	Checks if method has an attribute of the specified type.
+		 */
+		 bool hasAttribute(MonoClass* monoClass) const;
+
+		/**
+		 * @brief	Returns an instance of an attribute of the specified type. Returns null
+		 *			if the method doesn't have such an attribute.
+		 */
+		MonoObject* getAttribute(MonoClass* monoClass) const;
 
 	private:
 		friend class MonoClass;
 		friend class MonoProperty;
 
 		MonoMethod(::MonoMethod* method);
+		~MonoMethod();
+
+		void cacheSignature() const;
 
 		::MonoMethod* mMethod;
-		MonoClass* mReturnType;
 		void* mThunk;
+
+		mutable MonoClass* mCachedReturnType;
+		mutable MonoClass** mCachedParameters;
+		mutable UINT32 mCachedNumParameters;
+		mutable bool mIsStatic;
+		mutable bool mHasCachedSignature;
 	};
 }

+ 30 - 3
BansheeMono/Source/BsMonoClass.cpp

@@ -30,7 +30,8 @@ namespace BansheeEngine
 	}
 
 	MonoClass::MonoClass(const String& ns, const String& type, ::MonoClass* monoClass, const MonoAssembly* parentAssembly)
-		:mNamespace(ns), mTypeName(type), mClass(monoClass), mParentAssembly(parentAssembly), mHasCachedFields(false)
+		:mNamespace(ns), mTypeName(type), mClass(monoClass), mParentAssembly(parentAssembly), mHasCachedFields(false),
+		mHasCachedMethods(false)
 	{
 		mFullName = ns + "." + type;
 	}
@@ -59,7 +60,7 @@ namespace BansheeEngine
 		mProperties.clear();
 	}
 
-	MonoMethod& MonoClass::getMethod(const String& name, UINT32 numParams)
+	MonoMethod& MonoClass::getMethod(const String& name, UINT32 numParams) const
 	{
 		MethodId mehodId(name, numParams);
 		auto iterFind = mMethods.find(mehodId);
@@ -79,7 +80,7 @@ namespace BansheeEngine
 		return *newMethod;
 	}
 
-	MonoMethod* MonoClass::getMethodExact(const String& name, const String& signature)
+	MonoMethod* MonoClass::getMethodExact(const String& name, const String& signature) const
 	{
 		MethodId mehodId(name + "(" + signature + ")", 0);
 		auto iterFind = mMethods.find(mehodId);
@@ -182,6 +183,32 @@ namespace BansheeEngine
 		return mCachedFieldList;
 	}
 
+	const Vector<MonoMethod*> MonoClass::getAllMethods() const
+	{
+		if (mHasCachedMethods)
+			return mCachedMethodList;
+
+		mCachedMethodList.clear();
+
+		void* iter = nullptr;
+		::MonoMethod* curClassMethod = mono_class_get_methods(mClass, &iter);
+		while (curClassMethod != nullptr)
+		{
+			MonoMethodSignature* sig = mono_method_signature(curClassMethod);
+			const char* sigDesc = mono_signature_get_desc(sig, true);
+			const char* methodName = mono_method_get_name(curClassMethod);
+
+			MonoMethod* curMethod = getMethodExact(methodName, sigDesc);
+
+			mCachedMethodList.push_back(curMethod);
+
+			curClassMethod = mono_class_get_methods(mClass, &iter);
+		}
+
+		mHasCachedMethods = true;
+		return mCachedMethodList;
+	}
+
 	MonoObject* MonoClass::invokeMethod(const String& name, MonoObject* instance, void** params, UINT32 numParams)
 	{
 		return getMethod(name, numParams).invoke(instance, params);

+ 103 - 11
BansheeMono/Source/BsMonoMethod.cpp

@@ -1,15 +1,23 @@
 #include "BsMonoMethod.h"
 #include "BsMonoManager.h"
 #include "BsMonoUtil.h"
+#include "BsMonoClass.h"
 
 namespace BansheeEngine
 {
 	MonoMethod::MonoMethod(::MonoMethod* method)
-		:mMethod(method), mReturnType(nullptr)
+		:mMethod(method), mCachedReturnType(nullptr), mCachedParameters(nullptr), 
+		mCachedNumParameters(0), mIsStatic(false), mHasCachedSignature(false)
 	{
 		mThunk = mono_method_get_unmanaged_thunk(mMethod);
 	}
 
+	MonoMethod::~MonoMethod()
+	{
+		if (mCachedParameters != nullptr)
+			bs_free(mCachedParameters);
+	}
+
 	MonoObject* MonoMethod::invoke(MonoObject* instance, void** params)
 	{
 		MonoObject* exception = nullptr;
@@ -40,20 +48,104 @@ namespace BansheeEngine
 		return String(mono_method_get_name(mMethod));
 	}
 
-	MonoClass* MonoMethod::getReturnType()
+	MonoClass* MonoMethod::getReturnType() const
+	{
+		if (!mHasCachedSignature)
+			cacheSignature();
+
+		return mCachedReturnType;
+	}
+
+	UINT32 MonoMethod::getNumParameters() const
+	{
+		if (!mHasCachedSignature)
+			cacheSignature();
+
+		return mCachedNumParameters;
+	}
+
+	MonoClass* MonoMethod::getParameterType(UINT32 paramIdx) const
+	{
+		if (!mHasCachedSignature)
+			cacheSignature();
+
+		if (paramIdx >= mCachedNumParameters)
+			BS_EXCEPT(InvalidParametersException, "Parameter index out of range. Valid range is [0, " + toString(mCachedNumParameters - 1) + "]");
+
+		return mCachedParameters[paramIdx];
+	}
+
+	bool MonoMethod::isStatic() const
+	{
+		if (!mHasCachedSignature)
+			cacheSignature();
+
+		return mIsStatic;
+	}
+
+	bool MonoMethod::hasAttribute(MonoClass* monoClass) const
+	{
+		// TODO - Consider caching custom attributes or just initializing them all at load
+
+		MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(mMethod);
+		if (attrInfo == nullptr)
+			return false;
+
+		bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->_getInternalClass()) != 0;
+
+		mono_custom_attrs_free(attrInfo);
+
+		return hasAttr;
+	}
+
+	MonoObject* MonoMethod::getAttribute(MonoClass* monoClass) const
 	{
-		if(mReturnType != nullptr)
-			return mReturnType;
+		// TODO - Consider caching custom attributes or just initializing them all at load
 
-		MonoType* returnType = mono_signature_get_return_type(mono_method_signature(mMethod));
-		if(returnType == nullptr)
+		MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(mMethod);
+		if (attrInfo == nullptr)
 			return nullptr;
 
-		::MonoClass* returnClass = mono_class_from_mono_type(returnType);
-		if(returnClass == nullptr)
-			return nullptr;	
+		MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->_getInternalClass());
+
+		mono_custom_attrs_free(attrInfo);
+
+		return foundAttr;
+	}
+
+	void MonoMethod::cacheSignature() const
+	{
+		MonoMethodSignature* methodSignature = mono_method_signature(mMethod);
+
+		MonoType* returnType = mono_signature_get_return_type(methodSignature);
+		if (returnType != nullptr)
+		{
+			::MonoClass* returnClass = mono_class_from_mono_type(returnType);
+			if (returnClass != nullptr)
+				mCachedReturnType = MonoManager::instance().findClass(returnClass);
+		}
+
+		mCachedNumParameters = (UINT32)mono_signature_get_param_count(methodSignature);
+		if (mCachedParameters != nullptr)
+		{
+			bs_free(mCachedParameters);
+			mCachedParameters = nullptr;
+		}
+
+		if (mCachedNumParameters > 0)
+		{
+			mCachedParameters = (MonoClass**)bs_alloc(mCachedNumParameters * sizeof(MonoClass*));
+
+			void* iter = nullptr;
+			for (UINT32 i = 0; i < mCachedNumParameters; i++)
+			{
+				MonoType* curParamType = mono_signature_get_params(methodSignature, &iter);
+				::MonoClass* rawClass = mono_class_from_mono_type(curParamType);
+				mCachedParameters[i] = MonoManager::instance().findClass(rawClass);
+			}
+		}
 
-		mReturnType = MonoManager::instance().findClass(returnClass);
-		return mReturnType;
+		mIsStatic = !mono_signature_is_instance(methodSignature);
+		mHasCachedSignature = true;
 	}
 }

+ 2 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -81,6 +81,8 @@
     <Compile Include="Program.cs" />
     <Compile Include="ProjectLibrary.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Scene\DrawGizmo.cs" />
+    <Compile Include="Scene\Gizmos.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MBansheeEngine\MBansheeEngine.csproj">

+ 23 - 0
MBansheeEditor/Scene/DrawGizmo.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace BansheeEditor
+{
+    public enum DrawGizmoFlags
+    {
+        Selected = 0x01,
+        ParentSelected = 0x02,
+        NotSelected = 0x04,
+        Pickable = 0x08
+    }
+
+    [AttributeUsage(AttributeTargets.Method)]
+    public sealed class DrawGizmo : Attribute
+    {
+        private DrawGizmoFlags flags;
+
+        public DrawGizmo(DrawGizmoFlags flags)
+        {
+            this.flags = flags;
+        }
+    }
+}

+ 85 - 0
MBansheeEditor/Scene/Gizmos.cs

@@ -0,0 +1,85 @@
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class Gizmos
+    {
+        private Color _color;
+        private Matrix4 _transform;
+
+        public Color color
+        {
+            get { return _color; }
+            set { _color = value; Internal_SetColor(_color); }
+        }
+
+        public Matrix4 transform
+        {
+            get { return _transform; }
+            set { _transform = value; Internal_SetTransform(_transform); }
+        }
+
+        public void DrawCube(Vector3 position, Vector3 extents)
+        {
+            Internal_DrawCube(position, extents);
+        }
+
+        public void DrawSphere(Vector3 position, float radius)
+        {
+            Internal_DrawSphere(position, radius);
+        }
+
+        public void DrawWireCube(Vector3 position, Vector3 extents)
+        {
+            Internal_DrawWireCube(position, extents);
+        }
+
+        public void DrawWireSphere(Vector3 position, float radius)
+        {
+            Internal_DrawWireSphere(position, radius);
+        }
+
+        public void DrawLine(Vector3 start, Vector3 end)
+        {
+            Internal_DrawLine(start, end);
+        }
+
+        public void DrawFrustum(Vector3 position, float aspect, Degree FOV, float near, float far)
+        {
+            Internal_DrawFrustum(position, aspect, FOV, near, far);
+        }
+
+        public void DrawIcon(Vector3 position, SpriteTexture image, bool fixedScale)
+        {
+            Internal_DrawIcon(position, image, fixedScale);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetColor(Color color);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTransform(Matrix4 transform);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawCube(Vector3 position, Vector3 extents);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawSphere(Vector3 position, float radius);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawWireCube(Vector3 position, Vector3 extents);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawWireSphere(Vector3 position, float radius);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawLine(Vector3 start, Vector3 end);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawFrustum(Vector3 position, float aspect, Degree FOV, float near, float far);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DrawIcon(Vector3 position, SpriteTexture image, bool fixedScale);
+    }
+}

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -77,9 +77,11 @@
     <Compile Include="HideInInspector.cs" />
     <Compile Include="LocString.cs" />
     <Compile Include="ManagedResource.cs" />
+    <Compile Include="Math\Degree.cs" />
     <Compile Include="Math\MathEx.cs" />
     <Compile Include="Math\Matrix3.cs" />
     <Compile Include="Math\Matrix4.cs" />
+    <Compile Include="Math\Radian.cs" />
     <Compile Include="Math\RectI.cs" />
     <Compile Include="Math\Vector2I.cs" />
     <Compile Include="Program.cs" />

+ 132 - 0
MBansheeEngine/Math/Degree.cs

@@ -0,0 +1,132 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BansheeEngine
+{
+	public struct Degree
+	{
+        readonly float value;
+
+		public Degree(float value = 0.0f)
+	    {
+	        this.value = value;
+	    }
+
+        public Degree(Radian r)
+        {
+            this.value = r.GetDegrees();
+        }
+
+        public static implicit operator Degree(float value)
+        {
+            return new Degree(value);
+        }
+
+        public static implicit operator Degree(Radian r)
+        {
+            return new Degree(r.GetDegrees());
+        }
+
+	    public static explicit operator float(Degree d)
+	    {
+            return d.value;
+	    }
+
+	    public float GetDegrees()
+	    {
+	        return value;
+	    }
+
+        public float GetRadians()
+        {
+            return value * MathEx.Deg2Rad;
+        }
+
+	    public static Degree operator+(Degree a)
+	    {
+	        return a;
+	    }
+
+	    public static Degree operator+(Degree a, Degree b)
+	    {
+	        return new Degree(a.value + b.value);
+	    }
+
+        public static Degree operator+(Degree a, Radian r) 
+        { 
+            return new Degree (a.value + r.GetDegrees()); 
+        }
+
+	    public static Degree operator-(Degree a)
+	    {
+	        return new Degree(-a.value);
+	    }
+
+	    public static Degree operator-(Degree a, Degree b)
+	    {
+	        return new Degree(a.value - b.value);
+	    }
+
+        public static Degree operator-(Degree a, Radian r) 
+        { 
+            return new Degree (a.value - r.GetDegrees()); 
+        }
+
+        public static Degree operator*(Degree a, float s)
+        {
+            return new Degree(a.value * s);
+        }
+
+        public static Degree operator*(Degree a, Degree b)
+        {
+            return new Degree(a.value * b.value);
+        }
+
+        public static Degree operator/(Degree a, float s)
+        {
+            return new Degree(a.value / s);
+        }
+
+        public static Degree operator /(Degree a, Degree b)
+        {
+            return new Degree(a.value / b.value);
+        }
+
+	    public static bool operator<(Degree a, Degree b)
+	    {
+	        return a.value < b.value;
+	    }
+
+        public static bool operator>(Degree a, Degree b)
+        {
+            return a.value > b.value;
+        }
+
+        public static bool operator<=(Degree a, Degree b)
+        {
+            return a.value <= b.value;
+        }
+
+        public static bool operator>=(Degree a, Degree b)
+        {
+            return a.value >= b.value;
+        }
+
+        public static bool operator==(Degree a, Degree b)
+        {
+            return a.value == b.value;
+        }
+
+        public static bool operator!=(Degree a, Degree b)
+        {
+            return a.value != b.value;
+        }
+
+        public override int GetHashCode()
+        {
+            return value.GetHashCode();
+        }
+	};
+}

+ 6 - 6
MBansheeEngine/Math/Matrix3.cs

@@ -366,12 +366,12 @@ namespace BansheeEngine
             return Quaternion.FromRotationMatrix(this);
         }
 
-        public void ToAxisAngle(out Vector3 axis, out float degAngle)
+        public void ToAxisAngle(out Vector3 axis, out Degree angle)
         {
             float trace = m00 + m11 + m22;
             float cos = 0.5f*(trace-1.0f);
-            float radians = MathEx.Acos(cos);  // In [0, PI]
-            degAngle = radians*MathEx.Rad2Deg;
+            Radian radians = MathEx.Acos(cos);  // In [0, PI]
+            angle = radians.GetDegrees();
 
             if (radians > 0.0f)
             {
@@ -475,12 +475,12 @@ namespace BansheeEngine
 		    return mats[l.a]*(mats[l.b]*mats[l.c]);
         }
 
-        public static Matrix3 FromAxisAngle(Vector3 axis, float degAngle)
+        public static Matrix3 FromAxisAngle(Vector3 axis, Degree angle)
         {
             Matrix3 mat;
 
-            float cos = MathEx.Cos(degAngle * MathEx.Deg2Rad);
-            float sin = MathEx.Sin(degAngle * MathEx.Deg2Rad);
+            float cos = MathEx.Cos(angle.GetRadians());
+            float sin = MathEx.Sin(angle.GetRadians());
             float oneMinusCos = 1.0f - cos;
             float x2 = axis.x * axis.x;
             float y2 = axis.y * axis.y;

+ 10 - 13
MBansheeEngine/Math/Quaternion.cs

@@ -262,13 +262,13 @@ namespace BansheeEngine
             }
         }
 
-        public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegelta)
+        public static Quaternion RotateTowards(Quaternion from, Quaternion to, Degree maxDeg)
         {
-            float num = Angle(from, to);
+            Degree num = Angle(from, to);
             if (num == 0.0f)
                 return to;
 
-            float t = MathEx.Min(1f, maxDegelta / num);
+            float t = MathEx.Min(1f, (float)(maxDeg / num));
             return Slerp(from, to, t);
         }
 
@@ -280,20 +280,17 @@ namespace BansheeEngine
             return copy;
         }
 
-        /**
-         * @note Returns angle in degrees.
-         */
-        public static float Angle(Quaternion a, Quaternion b)
+        public static Degree Angle(Quaternion a, Quaternion b)
         {
             return (MathEx.Acos(MathEx.Min(MathEx.Abs(Dot(a, b)), 1.0f)) * 2.0f * MathEx.Rad2Deg);
         }
 
-        public void ToAxisAngle(out Vector3 axis, out float angleDeg)
+        public void ToAxisAngle(out Vector3 axis, out Degree angle)
         {
             float fSqrLength = x*x+y*y+z*z;
 		    if (fSqrLength > 0.0f)
 		    {
-                angleDeg = 2.0f * MathEx.Acos(w) * MathEx.Rad2Deg;
+                angle = 2.0f * MathEx.Acos(w) * MathEx.Rad2Deg;
 			    float fInvLength = MathEx.InvSqrt(fSqrLength);
 			    axis.x = x*fInvLength;
 			    axis.y = y*fInvLength;
@@ -302,7 +299,7 @@ namespace BansheeEngine
 		    else
 		    {
 			    // Angle is 0, so any axis will do
-                angleDeg = 0.0f;
+                angle = 0.0f;
 			    axis.x = 1.0f;
 			    axis.y = 0.0f;
 			    axis.z = 0.0f;
@@ -381,7 +378,7 @@ namespace BansheeEngine
             return rotation.ToEulerAngles(order);
         }
 
-        public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out float angleDeg)
+        public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angleDeg)
         {
             rotation.ToAxisAngle(out axis, out angleDeg);
         }
@@ -435,11 +432,11 @@ namespace BansheeEngine
             return quat;
         }
 
-        public static Quaternion FromAxisAngle(Vector3 axis, float angleDeg)
+        public static Quaternion FromAxisAngle(Vector3 axis, Degree angleDeg)
         {
             Quaternion quat;
 
-            float halfAngle = (0.5f*angleDeg*MathEx.Deg2Rad);
+            float halfAngle = (float)(0.5f*angleDeg*MathEx.Deg2Rad);
             float sin = MathEx.Sin(halfAngle);
             quat.w = MathEx.Cos(halfAngle);
             quat.x = sin * axis.x;

+ 132 - 0
MBansheeEngine/Math/Radian.cs

@@ -0,0 +1,132 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BansheeEngine
+{
+    public sealed class Radian
+    {
+		readonly float value;
+
+		public Radian(float value = 0.0f)
+	    {
+	        this.value = value;
+	    }
+
+        public Radian(Degree d)
+        {
+            this.value = d.GetRadians();
+        }
+
+        public static implicit operator Radian(float value)
+        {
+            return new Radian(value);
+        }
+
+        public static implicit operator Radian(Degree d)
+        {
+            return new Radian(d.GetRadians());
+        }
+
+        public static explicit operator float(Radian d)
+        {
+            return d.value;
+        }
+
+	    public float GetDegrees()
+	    {
+	        return value * MathEx.Rad2Deg;
+	    }
+
+        public float GetRadians()
+        {
+            return value;
+        }
+
+        public static Radian operator +(Radian a)
+	    {
+	        return a;
+	    }
+
+        public static Radian operator +(Radian a, Radian b)
+	    {
+            return new Radian(a.value + b.value);
+	    }
+
+        public static Radian operator +(Radian a, Degree d) 
+        {
+            return new Radian(a.value + d.GetRadians()); 
+        }
+
+        public static Radian operator -(Radian a)
+	    {
+            return new Radian(-a.value);
+	    }
+
+        public static Radian operator -(Radian a, Radian b)
+	    {
+            return new Radian(a.value - b.value);
+	    }
+
+        public static Radian operator -(Radian a, Degree d) 
+        {
+            return new Radian(a.value - d.GetRadians()); 
+        }
+
+        public static Radian operator *(Radian a, float s)
+        {
+            return new Radian(a.value * s);
+        }
+
+        public static Radian operator *(Radian a, Radian b)
+        {
+            return new Radian(a.value * b.value);
+        }
+
+        public static Radian operator /(Radian a, float s)
+        {
+            return new Radian(a.value / s);
+        }
+
+        public static Radian operator /(Radian a, Radian b)
+        {
+            return new Radian(a.value / b.value);
+        }
+
+        public static bool operator <(Radian a, Radian b)
+	    {
+	        return a.value < b.value;
+	    }
+
+        public static bool operator >(Radian a, Radian b)
+        {
+            return a.value > b.value;
+        }
+
+        public static bool operator <=(Radian a, Radian b)
+        {
+            return a.value <= b.value;
+        }
+
+        public static bool operator >=(Radian a, Radian b)
+        {
+            return a.value >= b.value;
+        }
+
+        public static bool operator ==(Radian a, Radian b)
+        {
+            return a.value == b.value;
+        }
+
+        public static bool operator !=(Radian a, Radian b)
+        {
+            return a.value != b.value;
+        }
+
+        public override int GetHashCode()
+        {
+            return value.GetHashCode();
+        }
+    }
+}

+ 1 - 0
SBansheeEditor/Include/BsEditorScriptManager.h

@@ -9,6 +9,7 @@ namespace BansheeEngine
 	{
 	public:
 		EditorScriptManager();
+		~EditorScriptManager();
 
 		void update();
 

+ 47 - 0
SBansheeEditor/Include/BsScriptGizmoManager.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	enum class DrawGizmoFlags
+	{
+		Selected = 0x01,
+		ParentSelected = 0x02,
+		NotSelected = 0x04,
+		Pickable = 0x08
+	};
+
+	class BS_SCR_BED_EXPORT ScriptGizmoManager : public Module<ScriptGizmoManager>
+	{
+		struct GizmoData
+		{
+			UINT32 assemblyId;
+			MonoClass* componentType;
+			MonoMethod* drawGizmosMethod;
+			UINT32 flags;
+		};
+
+	public:
+		ScriptGizmoManager(RuntimeScriptObjects& scriptObjectManager);
+		~ScriptGizmoManager();
+
+		void update();
+
+	private:
+		void reloadAssemblyMethods(MonoAssembly* assembly);
+		bool isValidDrawGizmoMethod(MonoMethod* method, MonoClass*& componentType, UINT32& drawGizmoFlags);
+
+		RuntimeScriptObjects& mScriptObjectManager;
+		HEvent mAssemblyRefreshedConn;
+
+		MonoClass* mDrawGizmoAttribute;
+		MonoField* mFlagsField;
+		Map<String, UINT32> mAssemblyNameToId;
+		Map<String, GizmoData> mGizmoDrawers;
+		UINT32 mNextAssemblyId;
+
+		Vector<MonoAssembly*> mDelayedLoad;
+	};
+}

+ 28 - 0
SBansheeEditor/Include/BsScriptGizmos.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsStringTable.h"
+#include "BsVector3.h"
+#include "BsMatrix4.h"
+#include "BsColor.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptGizmos : public ScriptObject<ScriptGizmos>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEditorAssemblyName, "BansheeEditor", "Gizmos")
+
+	private:
+		static void internal_SetColor(Color color);
+		static void internal_SetTransform(Matrix4 transform);
+		static void internal_DrawCube(Vector3 position, Vector3 extents);
+		static void internal_DrawSphere(Vector3 position, float radius);
+		static void internal_DrawWireCube(Vector3 position, Vector3 extents);
+		static void internal_DrawWireSphere(Vector3 position, float radius);
+		static void internal_DrawLine(Vector3 start, Vector3 end);
+		static void internal_DrawFrustum(Vector3 position, float aspect, Degree FOV, float near, float far);
+		static void internal_DrawIcon(Vector3 position, MonoObject* image, bool fixedScale);
+	};
+}

+ 4 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -232,6 +232,8 @@
     <ClInclude Include="Include\BsGUIResourceField.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorWindow.h" />
+    <ClInclude Include="Include\BsScriptGizmoManager.h" />
+    <ClInclude Include="Include\BsScriptGizmos.h" />
     <ClInclude Include="Include\BsScriptGUIColorField.h" />
     <ClInclude Include="Include\BsScriptGUIFloatField.h" />
     <ClInclude Include="Include\BsScriptGUIComponentFoldout.h" />
@@ -254,6 +256,8 @@
     <ClCompile Include="Source\BsGUIResourceField.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorWindow.cpp" />
+    <ClCompile Include="Source\BsScriptGizmoManager.cpp" />
+    <ClCompile Include="Source\BsScriptGizmos.cpp" />
     <ClCompile Include="Source\BsScriptGUIColorField.cpp" />
     <ClCompile Include="Source\BsScriptGUIFloatField.cpp" />
     <ClCompile Include="Source\BsScriptGUIComponentFoldout.cpp" />

+ 12 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -75,6 +75,12 @@
     <ClInclude Include="Include\BsScriptGUIFoldout.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptGizmos.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptGizmoManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -137,5 +143,11 @@
     <ClCompile Include="Source\BsScriptGUIFoldout.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptGizmos.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptGizmoManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 10 - 0
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -5,6 +5,7 @@
 #include "BsMonoClass.h"
 #include "BsMonoMethod.h"
 #include "BsRuntimeScriptObjects.h"
+#include "BsScriptGizmoManager.h"
 #include "BsTime.h"
 #include "BsMath.h"
 
@@ -24,6 +25,8 @@ namespace BansheeEngine
 
 		RuntimeScriptObjects::instance().refreshScriptObjects(BansheeEditorAssemblyName);
 
+		ScriptGizmoManager::startUp(RuntimeScriptObjects::instance());
+
 		mProgramEdClass = mEditorAssembly->getClass("BansheeEditor", "ProgramEd");
 		mUpdateMethod = &mProgramEdClass->getMethod("EditorUpdate");
 
@@ -34,6 +37,11 @@ namespace BansheeEngine
 		mUpdateMethod->invoke(nullptr, nullptr);
 	}
 
+	EditorScriptManager::~EditorScriptManager()
+	{
+		ScriptGizmoManager::shutDown();
+	}
+
 	void EditorScriptManager::update()
 	{
 		float curTime = gTime().getTime();
@@ -46,5 +54,7 @@ namespace BansheeEngine
 			INT32 numUpdates = Math::floorToInt(diff / EDITOR_UPDATE_RATE);
 			mLastUpdateTime += numUpdates * EDITOR_UPDATE_RATE;
 		}
+
+		ScriptGizmoManager::instance().update();
 	}
 }

+ 1 - 1
SBansheeEditor/Source/BsScriptEditorPlugin.cpp

@@ -23,6 +23,6 @@ namespace BansheeEngine
 
 	extern "C" BS_SCR_BED_EXPORT void unloadPlugin()
 	{
-		EditorScriptManager::shutDown();
+		ScriptGizmoManager::shutDown();
 	}
 }

+ 205 - 0
SBansheeEditor/Source/BsScriptGizmoManager.cpp

@@ -0,0 +1,205 @@
+#include "BsScriptGizmoManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsMonoAssembly.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoField.h"
+#include "BsMonoManager.h"
+#include "BsSceneManager.h"
+#include "BsSceneObject.h"
+#include "BsComponent.h"
+#include "BsManagedComponent.h"
+#include "BsGizmoManager.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGizmoManager::ScriptGizmoManager(RuntimeScriptObjects& scriptObjectManager)
+		:mScriptObjectManager(scriptObjectManager), mDrawGizmoAttribute(nullptr), mNextAssemblyId(0), mFlagsField(nullptr)
+	{
+		mScriptObjectManager.onAssemblyRefreshed.connect(std::bind(&ScriptGizmoManager::reloadAssemblyMethods, this, _1));
+
+		Vector<String> initializedAssemblyNames = mScriptObjectManager.getInitializedAssemblies();
+		for (auto& assemblyName : initializedAssemblyNames)
+		{
+			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);
+			if (assembly != nullptr)
+				reloadAssemblyMethods(assembly);
+		}
+	}
+
+	ScriptGizmoManager::~ScriptGizmoManager()
+	{
+		mAssemblyRefreshedConn.disconnect();
+	}
+
+	bool dummyIsSelected(const HSceneObject& so)
+	{
+		return false; // TODO - Replace with a call to Selection class once I have it
+	}
+
+	void ScriptGizmoManager::update()
+	{
+		HSceneObject rootSO = SceneManager::instance().getRootNode();
+
+		Stack<HSceneObject> todo;
+		todo.push(rootSO);
+
+		bool isParentSelected = false;
+		
+		while (!todo.empty())
+		{
+			HSceneObject curSO = todo.top();
+			todo.pop();
+
+			bool isSelected = dummyIsSelected(curSO);
+			bool isParentSelected = false; // TODO - Currently ignoring this
+
+			const Vector<HComponent>& components = curSO->getComponents();
+			for (auto& component : components)
+			{
+				if (rtti_is_of_type<ManagedComponent>(component.get()))
+				{
+					ManagedComponent* managedComponent = static_cast<ManagedComponent*>(component.get());
+
+					auto iterFind = mGizmoDrawers.find(managedComponent->getManagedFullTypeName());
+					if (iterFind != mGizmoDrawers.end())
+					{
+						UINT32 flags = iterFind->second.flags;
+
+						// TODO - Check if gizmo is to be drawn only when selected
+						// TODO - Set pickable if needed
+
+						bool drawGizmo = false;
+						if (((flags & (UINT32)DrawGizmoFlags::Selected) != 0) && isSelected)
+							drawGizmo = true;
+
+						if (((flags & (UINT32)DrawGizmoFlags::ParentSelected) != 0) && isParentSelected)
+							drawGizmo = true;
+
+						if (((flags & (UINT32)DrawGizmoFlags::NotSelected) != 0) && !isSelected && !isParentSelected)
+							drawGizmo = true;
+
+						if (drawGizmo)
+						{
+							bool pickable = (flags & (UINT32)DrawGizmoFlags::Pickable) != 0;
+							GizmoManager::instance().setPickable(pickable);
+
+							if ((flags & (UINT32)DrawGizmoFlags::Pickable) != 0)
+							{
+								void* params[1] = { managedComponent->getManagedInstance() };
+								iterFind->second.drawGizmosMethod->invoke(nullptr, params);
+							}
+						}
+					}
+				}
+			}
+
+			for (UINT32 i = 0; i < curSO->getNumChildren(); i++)
+				todo.push(curSO->getChild(i));
+		}
+	}
+
+	void ScriptGizmoManager::reloadAssemblyMethods(MonoAssembly* assembly)
+	{
+		String assemblyName = assembly->getName();
+
+		// If editor assembly, reload DrawGizmo attribute
+		if (assemblyName == BansheeEditorAssemblyName) 
+		{
+			mDrawGizmoAttribute = assembly->getClass("BansheeEditor", "DrawGizmo");
+			if (mDrawGizmoAttribute == nullptr)
+				BS_EXCEPT(InvalidStateException, "Cannot find DrawGizmo managed class.");
+
+			mFlagsField = mDrawGizmoAttribute->getField("flags");
+
+			// Load delayed assemblies first
+			for (auto iter = mDelayedLoad.rbegin(); iter != mDelayedLoad.rend(); ++iter)
+				reloadAssemblyMethods(*iter);
+
+			mDelayedLoad.clear();
+		}
+		else
+		{
+			// If we haven't loaded editor assembly yet, wait until we do before continuing
+			if (mDrawGizmoAttribute == nullptr)
+			{
+				mDelayedLoad.push_back(assembly);
+				return;
+			}
+		}
+
+		// If we had this assembly previously loaded, clear all of its methods
+		UINT32 assemblyId = 0;
+		auto iterFind = mAssemblyNameToId.find(assemblyName);
+		if (iterFind != mAssemblyNameToId.end())
+		{
+			assemblyId = iterFind->second;
+
+			Map<String, GizmoData> newGizmoDrawers;
+			for (auto& gizmoMethod : mGizmoDrawers)
+			{
+				if (gizmoMethod.second.assemblyId != assemblyId)
+					newGizmoDrawers[gizmoMethod.first] = gizmoMethod.second;
+			}
+
+			mGizmoDrawers.swap(newGizmoDrawers);
+		}
+		else
+		{
+			assemblyId = mNextAssemblyId++;
+			mAssemblyNameToId[assemblyName] = assemblyId;
+		}
+
+		// Find new gizmo drawer methods
+		const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
+		for (auto curClass : allClasses)
+		{
+			const Vector<MonoMethod*>& methods = curClass->getAllMethods();
+			for (auto& curMethod : methods)
+			{
+				UINT32 drawGizmoFlags = 0;
+				MonoClass* componentType = nullptr;
+				if (isValidDrawGizmoMethod(curMethod, componentType, drawGizmoFlags))
+				{
+					String fullComponentName = componentType->getFullName();
+					GizmoData& newGizmoData = mGizmoDrawers[fullComponentName];
+
+					newGizmoData.assemblyId = assemblyId;
+					newGizmoData.componentType = componentType;
+					newGizmoData.drawGizmosMethod = curMethod;
+					newGizmoData.flags = drawGizmoFlags;
+				}
+			}
+		}
+	}
+
+	bool ScriptGizmoManager::isValidDrawGizmoMethod(MonoMethod* method, MonoClass*& componentType, UINT32& drawGizmoFlags)
+	{
+		componentType = nullptr;
+		drawGizmoFlags = 0;
+
+		if (!method->hasAttribute(mDrawGizmoAttribute))
+			return false;
+
+		if (method->getNumParameters() != 1)
+			return false;
+
+		if (!method->isStatic())
+			return false;
+
+		MonoClass* paramType = method->getParameterType(0);
+		MonoClass* componentClass = mScriptObjectManager.getComponentClass();
+
+		if (!paramType->isSubClassOf(componentClass))
+			return false;
+
+		componentType = paramType;
+
+		MonoObject* drawGizmoAttrib = method->getAttribute(mDrawGizmoAttribute);
+		mFlagsField->getValue(drawGizmoAttrib, &drawGizmoFlags);
+
+		return true;
+	}
+}

+ 71 - 0
SBansheeEditor/Source/BsScriptGizmos.cpp

@@ -0,0 +1,71 @@
+#include "BsScriptGizmos.h"
+#include "BsScriptMeta.h"
+#include "BsMonoClass.h"
+#include "BsScriptSpriteTexture.h"
+#include "BsSpriteTexture.h"
+#include "BsGizmoManager.h"
+
+namespace BansheeEngine
+{
+	void ScriptGizmos::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_SetColor", &ScriptGizmos::internal_SetColor);
+		metaData.scriptClass->addInternalCall("Internal_SetTransform", &ScriptGizmos::internal_SetTransform);
+		metaData.scriptClass->addInternalCall("Internal_DrawCube", &ScriptGizmos::internal_DrawCube);
+		metaData.scriptClass->addInternalCall("Internal_DrawSphere", &ScriptGizmos::internal_DrawSphere);
+		metaData.scriptClass->addInternalCall("Internal_DrawWireCube", &ScriptGizmos::internal_DrawWireCube);
+		metaData.scriptClass->addInternalCall("Internal_DrawWireSphere", &ScriptGizmos::internal_DrawWireSphere);
+		metaData.scriptClass->addInternalCall("Internal_DrawLine", &ScriptGizmos::internal_DrawLine);
+		metaData.scriptClass->addInternalCall("Internal_DrawFrustum", &ScriptGizmos::internal_DrawFrustum);
+		metaData.scriptClass->addInternalCall("Internal_DrawIcon", &ScriptGizmos::internal_DrawIcon);
+	}
+
+	void internal_SetColor(Color color)
+	{
+		GizmoManager::instance().setColor(color);
+	}
+
+	void internal_SetTransform(Matrix4 transform)
+	{
+		GizmoManager::instance().setTransform(transform);
+	}
+
+	void internal_DrawCube(Vector3 position, Vector3 extents)
+	{
+		GizmoManager::instance().drawCube(position, extents);
+	}
+
+	void internal_DrawSphere(Vector3 position, float radius)
+	{
+		GizmoManager::instance().drawSphere(position, radius);
+	}
+
+	void internal_DrawWireCube(Vector3 position, Vector3 extents)
+	{
+		GizmoManager::instance().drawWireCube(position, extents);
+	}
+
+	void internal_DrawWireSphere(Vector3 position, float radius)
+	{
+		GizmoManager::instance().drawWireSphere(position, radius);
+	}
+
+	void internal_DrawLine(Vector3 start, Vector3 end)
+	{
+		GizmoManager::instance().drawLine(start, end);
+	}
+
+	void internal_DrawFrustum(Vector3 position, float aspect, Degree FOV, float near, float far)
+	{
+		GizmoManager::instance().drawFrustum(position, aspect, FOV, near, far);
+	}
+
+	void ScriptGizmos::internal_DrawIcon(Vector3 position, MonoObject* image, bool fixedScale)
+	{
+		HSpriteTexture nativeTexture;
+		if (image != nullptr)
+			nativeTexture = ScriptSpriteTexture::toNative(image)->getInternalValue();
+
+		GizmoManager::instance().drawIcon(position, nativeTexture, fixedScale);
+	}
+}

+ 4 - 0
SBansheeEngine/Include/BsRuntimeScriptObjects.h

@@ -17,6 +17,8 @@ namespace BansheeEngine
 		bool getSerializableObjectInfo(const String& ns, const String& typeName, std::shared_ptr<ManagedSerializableObjectInfo>& outInfo);
 		bool hasSerializableObjectInfo(const String& ns, const String& typeName);
 
+		Vector<String> getInitializedAssemblies() const;
+
 		MonoClass* getSystemArrayClass() const { return mSystemArrayClass; }
 		MonoClass* getSystemGenericListClass() const { return mSystemGenericListClass; }
 		MonoClass* getSystemGenericDictionaryClass() const { return mSystemGenericDictionaryClass; }
@@ -27,6 +29,8 @@ namespace BansheeEngine
 		MonoClass* getSpriteTextureClass() const { return mSpriteTextureClass; }
 
 		ManagedSerializableTypeInfoPtr determineType(MonoClass* monoClass);
+
+		Event<void(MonoAssembly*)> onAssemblyRefreshed;
 	private:
 		UnorderedMap<String, std::shared_ptr<ManagedSerializableAssemblyInfo>> mAssemblyInfos;
 		bool mBaseTypesInitialized;

+ 1 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -54,6 +54,7 @@ namespace BansheeEngine
 	class ManagedSerializableFieldInfo;
 	class ManagedResource;
 	class ManagedResourceMetaData;
+	class RuntimeScriptObjects;
 
 	typedef GameObjectHandle<ManagedComponent> HManagedComponent;
 	typedef ResourceHandle<ManagedResource> HManagedResource;

+ 11 - 0
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -27,6 +27,15 @@ namespace BansheeEngine
 
 	}
 
+	Vector<String> RuntimeScriptObjects::getInitializedAssemblies() const
+	{
+		Vector<String> initializedAssemblies;
+		for (auto& assemblyPair : mAssemblyInfos)
+			initializedAssemblies.push_back(assemblyPair.first);
+
+		return initializedAssemblies;
+	}
+
 	void RuntimeScriptObjects::refreshScriptObjects(const String& assemblyName)
 	{
 		clearScriptObjects(assemblyName);
@@ -142,6 +151,8 @@ namespace BansheeEngine
 				base = base->getBaseClass();
 			}
 		}
+
+		onAssemblyRefreshed(curAssembly);
 	}
 
 	ManagedSerializableTypeInfoPtr RuntimeScriptObjects::determineType(MonoClass* monoClass)

+ 5 - 0
SceneView.txt

@@ -4,10 +4,15 @@ TODO:
 
 IMMEDIATE:
  - SceneGrid is very ugly. Consider using default lines for now and come back with a better approach later.
+   - Potentially enable line AA?
  - In Picking code I don't set main texture when rendering with alpha
  - Picking code is completely untested and will likely need major fixing
  - Disable DX9 for editor as I will likely want to use geometry shaders for icon rendering, and possibly new AA line shader
    - Or just use MeshHeap and update the icon/lines every frame?
+ - Test all the new DrawHelper3D methods
+
+LATER:
+ - Need a way to render text for gizmos and handles, and in scene in general
 
 ----------------------------------------------------------------------
 Handles