Browse Source

Scene handle rendering & interaction can now be separated per layer

BearishSun 10 years ago
parent
commit
5ab1368c9e
30 changed files with 2488 additions and 2328 deletions
  1. 263 257
      BansheeEditor/Include/BsHandleDrawManager.h
  2. 183 178
      BansheeEditor/Include/BsHandleSlider.h
  3. 112 111
      BansheeEditor/Include/BsHandleSliderDisc.h
  4. 69 68
      BansheeEditor/Include/BsHandleSliderLine.h
  5. 79 78
      BansheeEditor/Include/BsHandleSliderPlane.h
  6. 284 279
      BansheeEditor/Source/BsHandleDrawManager.cpp
  7. 124 124
      BansheeEditor/Source/BsHandleSlider.cpp
  8. 182 182
      BansheeEditor/Source/BsHandleSliderDisc.cpp
  9. 83 83
      BansheeEditor/Source/BsHandleSliderLine.cpp
  10. 131 129
      BansheeEditor/Source/BsHandleSliderManager.cpp
  11. 91 91
      BansheeEditor/Source/BsHandleSliderPlane.cpp
  12. 15 5
      BansheeEngine/Include/BsDrawHelper.h
  13. 130 41
      BansheeEngine/Source/BsDrawHelper.cpp
  14. 13 0
      MBansheeEditor/Scene/HandleDrawing.cs
  15. 5 3
      MBansheeEditor/Scene/HandleSliderDisc.cs
  16. 5 3
      MBansheeEditor/Scene/HandleSliderLine.cs
  17. 6 4
      MBansheeEditor/Scene/HandleSliderPlane.cs
  18. 245 244
      MBansheeEditor/Scene/MoveHandle.cs
  19. 245 244
      MBansheeEditor/Scene/RotateHandle.cs
  20. 183 182
      MBansheeEditor/Scene/ScaleHandle.cs
  21. 8 4
      MBansheeEditor/Scene/SceneAxesHandle.cs
  22. 1 0
      MBansheeEditor/Scene/SceneWindow.cs
  23. 1 0
      SBansheeEditor/Include/BsScriptHandleDrawing.h
  24. 2 2
      SBansheeEditor/Include/BsScriptHandleSliderDisc.h
  25. 2 2
      SBansheeEditor/Include/BsScriptHandleSliderLine.h
  26. 4 2
      SBansheeEditor/Include/BsScriptHandleSliderPlane.h
  27. 6 0
      SBansheeEditor/Source/BsScriptHandleDrawing.cpp
  28. 4 4
      SBansheeEditor/Source/BsScriptHandleSliderDisc.cpp
  29. 6 4
      SBansheeEditor/Source/BsScriptHandleSliderLine.cpp
  30. 6 4
      SBansheeEditor/Source/BsScriptHandleSliderPlane.cpp

+ 263 - 257
BansheeEditor/Include/BsHandleDrawManager.h

@@ -1,258 +1,264 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsGpuParams.h"
-
-namespace BansheeEngine
-{
-	class HandleDrawManagerCore;
-
-	/**
-	 * @brief	Allows you to easily draw various kinds of simple shapes, primarily
-	 *			used for drawing handles in the scene view.
-	 *
-	 *			Drawn elements only persist for a single draw call and need to be re-queued
-	 *			after.
-	 */
-	class BS_ED_EXPORT HandleDrawManager
-	{
-	public:
-		HandleDrawManager();
-		~HandleDrawManager();
-
-		/**
-		 * @brief	Sets the color of all the following draw* calls.
-		 */
-		void setColor(const Color& color);
-
-		/**
-		 * @brief	Sets the transform matrix that will be applied to all
-		 *			following draw* calls.
-		 */
-		void setTransform(const Matrix4& transform);
-
-		/**
-		 * @brief	Draws a solid cuboid.
-		 *
-		 * @param	position	Center of the cuboid.
-		 * @param	extents		Radius of the cuboid in all directions.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawCube(const Vector3& position, const Vector3& extents, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a solid sphere.
-		 *
-		 * @param	position	Center of the sphere.
-		 * @param	radius		Radius of the sphere.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawSphere(const Vector3& position, float radius, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a wireframe cuboid.
-		 *
-		 * @param	position	Center of the cuboid.
-		 * @param	extents		Radius of the cuboid in all directions.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawWireCube(const Vector3& position, const Vector3& extents, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a wireframe sphere.
-		 *
-		 * @param	position	Center of the sphere.
-		 * @param	radius		Radius of the sphere.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawWireSphere(const Vector3& position, float radius, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a solid cone.
-		 *
-		 * @param	base		Position of the center of the base of the cone.
-		 * @param	normal		Orientation of the cone, pointing from center base to the tip of the cone.
-		 * @param	height		Height of the cone (along the normal).
-		 * @param	radius		Radius of the base of the cone.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawCone(const Vector3& base, const Vector3& normal, float height, float radius, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a line.
-		 *
-		 * @param	start		Starting point for the line.
-		 * @param	end			Ending point for the line.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawLine(const Vector3& start, const Vector3& end, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a double-sided solid disc.
-		 *
-		 * @param	position	Center of the disc.
-		 * @param	normal		Orientation of the disc, pointing in the direction the disc is visible in.
-		 * @param	radius		Radius of the disc.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawDisc(const Vector3& position, const Vector3& normal, float radius, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a wireframe disc.
-		 *
-		 * @param	position	Center of the disc.
-		 * @param	normal		Orientation of the disc, pointing in the direction the disc is visible in.
-		 * @param	radius		Radius of the disc.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawWireDisc(const Vector3& position, const Vector3& normal, float radius, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a double-sided solid arc.
-		 *
-		 * @param	position	Center of the arc.
-		 * @param	normal		Orientation of the arc, pointing in the direction the arc is visible in.
-		 * @param	radius		Radius of the arc.
-		 * @param	startAngle	Angle at which to start the arc.
-		 * @param	amountAngle	Length of the arc.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a wireframe arc.
-		 *
-		 * @param	position	Center of the arc.
-		 * @param	normal		Orientation of the arc, pointing in the direction the arc is visible in.
-		 * @param	radius		Radius of the arc.
-		 * @param	startAngle	Angle at which to start the arc.
-		 * @param	amountAngle	Length of the arc.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawWireArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f);
-
-		/**
-		 * @brief	Draws a double-sided solid rectangle.
-		 *
-		 * @param	area		Position and size of the rectangle.
-		 * @param	size		Uniform scale of the object.
-		 */
-		void drawRect(const Rect3& area, float size = 1.0f);
-
-		/**
-		 * @brief	Queues all the handle draw commands executed so far for rendering. All commands
-		 *			are cleared and will need to be called again to draw them again.
-		 */
-		void draw(const CameraPtr& camera);
-
-	private:
-		friend class HandleDrawManagerCore;
-
-		/**
-		 * @brief	Initializes the core thread portion of the draw manager.
-		 *
-		 * @param	wireMat		Material used for drawing the wireframe objects.
-		 * @param	solidMat	Material used for drawing the solid objects.
-		 */
-		void initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat);
-
-		/**
-		 * @brief	Destroys the core thread portion of the draw manager.
-		 */
-		void destroyCore(HandleDrawManagerCore* core);
-
-		static const UINT32 SPHERE_QUALITY;
-		static const UINT32 WIRE_SPHERE_QUALITY;
-		static const UINT32 ARC_QUALITY;
-
-		Matrix4 mTransform;
-		std::atomic<HandleDrawManagerCore*> mCore;
-		DrawHelper* mDrawHelper;
-	};
-
-	/**
-	 * @brief	Core thread specific portion of the HandleDrawManager that
-	 *			handles actual rendering.
-	 */
-	class BS_ED_EXPORT HandleDrawManagerCore
-	{
-		/**
-		 * @brief	Contains information about the material used for 
-		 *			drawing solid objects and its parameters.
-		 */
-		struct SolidMaterialData
-		{
-			SPtr<MaterialCore> mat;
-			GpuParamMat4Core mViewProj;
-			GpuParamVec4Core mViewDir;
-		};
-
-		/**
-		 * @brief	Contains information about the material used for 
-		 *			drawing wireframe objects and its parameters.
-		 */
-		struct WireMaterialData
-		{
-			SPtr<MaterialCore> mat;
-			GpuParamMat4Core mViewProj;
-		};
-
-		/**
-		 * @brief	Type of mesh that can be drawn.
-		 */
-		enum class MeshType
-		{
-			Solid, Wire
-		};
-
-		/**
-		 * @brief	Contains data about a render mesh.
-		 */
-		struct MeshData
-		{
-			MeshData(const SPtr<MeshCoreBase>& mesh, MeshType type)
-				:mesh(mesh), type(type)
-			{ }
-
-			SPtr<MeshCoreBase> mesh;
-			MeshType type;
-		};
-
-		struct PrivatelyConstruct { };
-
-	public:
-		HandleDrawManagerCore(const PrivatelyConstruct& dummy) { }
-		~HandleDrawManagerCore();
-
-	private:
-		friend class HandleDrawManager;
-
-		/**
-		 * @brief	Initializes the object. Must be called right after construction.
-		 *
-		 * @param	wireMat		Material used for drawing the wireframe objects.
-		 * @param	solidMat	Material used for drawing the solid objects.
-		 */
-		void initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat);
-
-		/**
-		 * @brief	Updates the data that will be used for rendering the new frame.
-		 *
-		 * @param	camera	Camera to render to.
-		 * @param	meshes	Meshes to render.
-		 */
-		void updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes);
-
-		/**
-		 * @brief	Callback triggered by the renderer. Draws the stored meshes.
-		 */
-		void render();
-
-		SPtr<CameraCore> mCamera;
-		Vector<MeshData> mMeshes;
-
-		// Immutable
-		SolidMaterialData mSolidMaterial;
-		WireMaterialData mWireMaterial;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsGpuParams.h"
+
+namespace BansheeEngine
+{
+	class HandleDrawManagerCore;
+
+	/**
+	 * @brief	Allows you to easily draw various kinds of simple shapes, primarily
+	 *			used for drawing handles in the scene view.
+	 *
+	 *			Drawn elements only persist for a single draw call and need to be re-queued
+	 *			after.
+	 */
+	class BS_ED_EXPORT HandleDrawManager
+	{
+	public:
+		HandleDrawManager();
+		~HandleDrawManager();
+
+		/**
+		 * @brief	Sets the color of all the following draw* calls.
+		 */
+		void setColor(const Color& color);
+
+		/**
+		 * @brief	Sets the transform matrix that will be applied to all
+		 *			following draw* calls.
+		 */
+		void setTransform(const Matrix4& transform);
+
+		/**
+		 * Sets the layer bitfield that controls whether a handle is considered visible in a specific camera. Handle layer 
+		 * must match camera layer in order for the camera to render it
+		 */
+		void setLayer(UINT64 layer);
+
+		/**
+		 * @brief	Draws a solid cuboid.
+		 *
+		 * @param	position	Center of the cuboid.
+		 * @param	extents		Radius of the cuboid in all directions.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawCube(const Vector3& position, const Vector3& extents, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a solid sphere.
+		 *
+		 * @param	position	Center of the sphere.
+		 * @param	radius		Radius of the sphere.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawSphere(const Vector3& position, float radius, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a wireframe cuboid.
+		 *
+		 * @param	position	Center of the cuboid.
+		 * @param	extents		Radius of the cuboid in all directions.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawWireCube(const Vector3& position, const Vector3& extents, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a wireframe sphere.
+		 *
+		 * @param	position	Center of the sphere.
+		 * @param	radius		Radius of the sphere.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawWireSphere(const Vector3& position, float radius, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a solid cone.
+		 *
+		 * @param	base		Position of the center of the base of the cone.
+		 * @param	normal		Orientation of the cone, pointing from center base to the tip of the cone.
+		 * @param	height		Height of the cone (along the normal).
+		 * @param	radius		Radius of the base of the cone.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawCone(const Vector3& base, const Vector3& normal, float height, float radius, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a line.
+		 *
+		 * @param	start		Starting point for the line.
+		 * @param	end			Ending point for the line.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawLine(const Vector3& start, const Vector3& end, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a double-sided solid disc.
+		 *
+		 * @param	position	Center of the disc.
+		 * @param	normal		Orientation of the disc, pointing in the direction the disc is visible in.
+		 * @param	radius		Radius of the disc.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawDisc(const Vector3& position, const Vector3& normal, float radius, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a wireframe disc.
+		 *
+		 * @param	position	Center of the disc.
+		 * @param	normal		Orientation of the disc, pointing in the direction the disc is visible in.
+		 * @param	radius		Radius of the disc.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawWireDisc(const Vector3& position, const Vector3& normal, float radius, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a double-sided solid arc.
+		 *
+		 * @param	position	Center of the arc.
+		 * @param	normal		Orientation of the arc, pointing in the direction the arc is visible in.
+		 * @param	radius		Radius of the arc.
+		 * @param	startAngle	Angle at which to start the arc.
+		 * @param	amountAngle	Length of the arc.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a wireframe arc.
+		 *
+		 * @param	position	Center of the arc.
+		 * @param	normal		Orientation of the arc, pointing in the direction the arc is visible in.
+		 * @param	radius		Radius of the arc.
+		 * @param	startAngle	Angle at which to start the arc.
+		 * @param	amountAngle	Length of the arc.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawWireArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size = 1.0f);
+
+		/**
+		 * @brief	Draws a double-sided solid rectangle.
+		 *
+		 * @param	area		Position and size of the rectangle.
+		 * @param	size		Uniform scale of the object.
+		 */
+		void drawRect(const Rect3& area, float size = 1.0f);
+
+		/**
+		 * @brief	Queues all the handle draw commands executed so far for rendering. All commands
+		 *			are cleared and will need to be called again to draw them again.
+		 */
+		void draw(const CameraPtr& camera);
+
+	private:
+		friend class HandleDrawManagerCore;
+
+		/**
+		 * @brief	Initializes the core thread portion of the draw manager.
+		 *
+		 * @param	wireMat		Material used for drawing the wireframe objects.
+		 * @param	solidMat	Material used for drawing the solid objects.
+		 */
+		void initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat);
+
+		/**
+		 * @brief	Destroys the core thread portion of the draw manager.
+		 */
+		void destroyCore(HandleDrawManagerCore* core);
+
+		static const UINT32 SPHERE_QUALITY;
+		static const UINT32 WIRE_SPHERE_QUALITY;
+		static const UINT32 ARC_QUALITY;
+
+		Matrix4 mTransform;
+		std::atomic<HandleDrawManagerCore*> mCore;
+		DrawHelper* mDrawHelper;
+	};
+
+	/**
+	 * @brief	Core thread specific portion of the HandleDrawManager that
+	 *			handles actual rendering.
+	 */
+	class BS_ED_EXPORT HandleDrawManagerCore
+	{
+		/**
+		 * @brief	Contains information about the material used for 
+		 *			drawing solid objects and its parameters.
+		 */
+		struct SolidMaterialData
+		{
+			SPtr<MaterialCore> mat;
+			GpuParamMat4Core mViewProj;
+			GpuParamVec4Core mViewDir;
+		};
+
+		/**
+		 * @brief	Contains information about the material used for 
+		 *			drawing wireframe objects and its parameters.
+		 */
+		struct WireMaterialData
+		{
+			SPtr<MaterialCore> mat;
+			GpuParamMat4Core mViewProj;
+		};
+
+		/**
+		 * @brief	Type of mesh that can be drawn.
+		 */
+		enum class MeshType
+		{
+			Solid, Wire
+		};
+
+		/**
+		 * @brief	Contains data about a render mesh.
+		 */
+		struct MeshData
+		{
+			MeshData(const SPtr<MeshCoreBase>& mesh, MeshType type)
+				:mesh(mesh), type(type)
+			{ }
+
+			SPtr<MeshCoreBase> mesh;
+			MeshType type;
+		};
+
+		struct PrivatelyConstruct { };
+
+	public:
+		HandleDrawManagerCore(const PrivatelyConstruct& dummy) { }
+		~HandleDrawManagerCore();
+
+	private:
+		friend class HandleDrawManager;
+
+		/**
+		 * @brief	Initializes the object. Must be called right after construction.
+		 *
+		 * @param	wireMat		Material used for drawing the wireframe objects.
+		 * @param	solidMat	Material used for drawing the solid objects.
+		 */
+		void initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat);
+
+		/**
+		 * @brief	Updates the data that will be used for rendering the new frame.
+		 *
+		 * @param	camera	Camera to render to.
+		 * @param	meshes	Meshes to render.
+		 */
+		void updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes);
+
+		/**
+		 * @brief	Callback triggered by the renderer. Draws the stored meshes.
+		 */
+		void render();
+
+		SPtr<CameraCore> mCamera;
+		Vector<MeshData> mMeshes;
+
+		// Immutable
+		SolidMaterialData mSolidMaterial;
+		WireMaterialData mWireMaterial;
+	};
 }

+ 183 - 178
BansheeEditor/Include/BsHandleSlider.h

@@ -1,179 +1,184 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsVector2I.h"
-#include "BsMatrix4.h"
-#include "BsQuaternion.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Base class for all handle sliders. A handle slider is geometry that the user
-	 *			can interact with by selecting or dragging (i.e. sliding) it. Sliders generally
-	 *			output a one- or multi-dimensional delta value that signals the drag amount 
-	 *			(and/or direction).
-	 */
-	class BS_ED_EXPORT HandleSlider
-	{
-	public:
-		/**
-		 * @brief	Possible states the slider can be in.
-		 */
-		enum class State
-		{
-			Inactive, /**< Slider is not being interacted with. */
-			Active, /**< Slider is clicked on and being dragged. */
-			Hover /**< Slider is being hovered over but isn't clicked on. */
-		};
-
-		/**
-		 * @brief	Constructs a new handle slider.
-		 *
-		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
-		 *						area in the viewport regardless of distance from camera. 
-		 */
-		HandleSlider(bool fixedScale);
-		virtual ~HandleSlider() { }
-
-		/**
-		 * @brief	Attempts to find an intersection between the provided ray and the slider geometry.
-		 *
-		 * @param	ray	Ray in world space to try to interect with geometry.
-		 * @param	t	Position of the intersection along the ray. Only if intersection happened.
-		 *
-		 * @return	Whether an intersection was detected.
-		 */
-		virtual bool intersects(const Ray& ray, float& t) const = 0;
-
-		/**
-		 * @brief	Updates a slider that is currently active (being dragged).
-		 *
-		 * @param	camera		Camera through which we're interacting with the slider.
-		 * @param	inputDelta	Pointer movement since the last time this method was called.
-		 */
-		virtual void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) = 0;
-
-		/**
-		 * @brief	Updates the state of the slider. Must be called every frame.
-		 *
-		 * @param	camera	Camera through which we're interacting with the slider.
-		 */
-		void update(const CameraPtr& camera);
-
-		/**
-		 * @brief	Returns the state the slider is currently in.
-		 */
-		State getState() const { return mState; }
-		
-		/**
-		 * @brief	Returns if fixed scale is enabled. If enabled the handle slider will 
-		 *			always try to maintain the same visible area in the viewport regardless 
-		 *			of distance from camera.
-		 */
-		bool getFixedScale() const { return mFixedScale; }
-
-		/**
-		 * @brief	Sets the world position of the slider.
-		 */
-		void setPosition(const Vector3& position);
-
-		/**
-		 * @brief	Sets the world rotation of the slider.
-		 */
-		void setRotation(const Quaternion& rotation);
-
-		/**
-		 * @brief	Sets the scale of the slider.
-		 */
-		void setScale(const Vector3& scale);
-
-		/**
-		 * @brief	Gets the world position of the slider.
-		 */
-		const Vector3& getPosition() const { return mPosition; }
-
-		/**
-		 * @brief	Gets the world rotation of the slider.
-		 */
-		const Quaternion& getRotation() const { return mRotation; }
-
-		/**
-		 * @brief	Gets the scale of the slider.
-		 */
-		const Vector3& getScale() const { return mScale; }
-
-	protected:
-		friend class HandleSliderManager;
-
-		/**
-		 * @brief	Toggles the slider state to inactive.
-		 */
-		void setInactive();
-
-		/**
-		 * @brief	Toggles the slider state to active.
-		 *
-		 * @param	camera		Camera through which the slider was activated.
-		 * @param	pointerPos	Position of the pointer when the slider was activated.
-		 */
-		void setActive(const CameraPtr& camera, const Vector2I& pointerPos);
-
-		/**
-		 * @brief	Toggles the slider state to hovered.
-		 */
-		void setHover();
-
-		/**
-		 * @brief	Gets the slider transform depending on set position, rotation and scale values.
-		 */
-		const Matrix4& getTransform() const;
-
-		/**
-		 * @brief	Gets the inverse of the slider transform depending on 
-		 *			set position, rotation and scale values.
-		 */
-		const Matrix4& getTransformInv() const;
-
-		/**
-		 * @brief	Triggered when the slider state is changed to active.
-		 */
-		virtual void activate(const CameraPtr& camera, const Vector2I& pointerPos) { }
-
-		/**
-		 * @brief	Triggered when the slider state is changed from active to some other state.
-		 */
-		virtual void reset() { }
-
-		/**
-		 * @brief	Updates the internal transform from the stored position, rotation and scale values.
-		 */
-		void updateCachedTransform() const;
-
-		/**
-		 * @brief	Calculates amount of movement along the provided ray depending on pointer movement.
-		 *
-		 * @param	camera			Camera on which the pointer movement is occurring.
-		 * @param	position		Position of the ray to calculate movement on.
-		 * @param	direction		Direction of the ray to calculate movement on. Must be normalized.
-		 * @param	pointerStart	Starting position of the pointer when movement started, in pixels relative to provided camera.
-		 * @param	pointerEnd		Current position of the pointer, in pixels relative to provided camera.
-		 */
-		float calcDelta(const CameraPtr& camera, const Vector3& position, const Vector3& direction,
-			const Vector2I& pointerStart, const Vector2I& pointerEnd);
-
-		bool mFixedScale;
-
-		Vector3 mPosition;
-		Quaternion mRotation;
-		Vector3 mScale;
-		float mDistanceScale;
-
-		Vector2I mStartPointerPos;
-		Vector2I mCurrentPointerPos;
-		State mState;
-
-		mutable bool mTransformDirty;
-		mutable Matrix4 mTransform;
-		mutable Matrix4 mTransformInv;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsVector2I.h"
+#include "BsMatrix4.h"
+#include "BsQuaternion.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Base class for all handle sliders. A handle slider is geometry that the user
+	 *			can interact with by selecting or dragging (i.e. sliding) it. Sliders generally
+	 *			output a one- or multi-dimensional delta value that signals the drag amount 
+	 *			(and/or direction).
+	 */
+	class BS_ED_EXPORT HandleSlider
+	{
+	public:
+		/**
+		 * @brief	Possible states the slider can be in.
+		 */
+		enum class State
+		{
+			Inactive, /**< Slider is not being interacted with. */
+			Active, /**< Slider is clicked on and being dragged. */
+			Hover /**< Slider is being hovered over but isn't clicked on. */
+		};
+
+		/**
+		 * @brief	Constructs a new handle slider.
+		 *
+		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
+		 *						area in the viewport regardless of distance from camera. 
+		 * @param	layer		Layer that allows filtering of which sliders are interacted with from a specific camera.
+		 */
+		HandleSlider(bool fixedScale, UINT64 layer);
+		virtual ~HandleSlider() { }
+
+		/**
+		 * @brief	Attempts to find an intersection between the provided ray and the slider geometry.
+		 *
+		 * @param	ray	Ray in world space to try to interect with geometry.
+		 * @param	t	Position of the intersection along the ray. Only if intersection happened.
+		 *
+		 * @return	Whether an intersection was detected.
+		 */
+		virtual bool intersects(const Ray& ray, float& t) const = 0;
+
+		/**
+		 * @brief	Updates a slider that is currently active (being dragged).
+		 *
+		 * @param	camera		Camera through which we're interacting with the slider.
+		 * @param	inputDelta	Pointer movement since the last time this method was called.
+		 */
+		virtual void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) = 0;
+
+		/**
+		 * @brief	Updates the state of the slider. Must be called every frame.
+		 *
+		 * @param	camera	Camera through which we're interacting with the slider.
+		 */
+		void update(const CameraPtr& camera);
+
+		/**
+		 * @brief	Returns the state the slider is currently in.
+		 */
+		State getState() const { return mState; }
+		
+		/**
+		 * @brief	Returns if fixed scale is enabled. If enabled the handle slider will 
+		 *			always try to maintain the same visible area in the viewport regardless 
+		 *			of distance from camera.
+		 */
+		bool getFixedScale() const { return mFixedScale; }
+
+		/** Returns a layer that determines which sliders are interacted with from a specific camera. */
+		UINT64 getLayer() const { return mLayer; }
+
+		/**
+		 * @brief	Sets the world position of the slider.
+		 */
+		void setPosition(const Vector3& position);
+
+		/**
+		 * @brief	Sets the world rotation of the slider.
+		 */
+		void setRotation(const Quaternion& rotation);
+
+		/**
+		 * @brief	Sets the scale of the slider.
+		 */
+		void setScale(const Vector3& scale);
+
+		/**
+		 * @brief	Gets the world position of the slider.
+		 */
+		const Vector3& getPosition() const { return mPosition; }
+
+		/**
+		 * @brief	Gets the world rotation of the slider.
+		 */
+		const Quaternion& getRotation() const { return mRotation; }
+
+		/**
+		 * @brief	Gets the scale of the slider.
+		 */
+		const Vector3& getScale() const { return mScale; }
+
+	protected:
+		friend class HandleSliderManager;
+
+		/**
+		 * @brief	Toggles the slider state to inactive.
+		 */
+		void setInactive();
+
+		/**
+		 * @brief	Toggles the slider state to active.
+		 *
+		 * @param	camera		Camera through which the slider was activated.
+		 * @param	pointerPos	Position of the pointer when the slider was activated.
+		 */
+		void setActive(const CameraPtr& camera, const Vector2I& pointerPos);
+
+		/**
+		 * @brief	Toggles the slider state to hovered.
+		 */
+		void setHover();
+
+		/**
+		 * @brief	Gets the slider transform depending on set position, rotation and scale values.
+		 */
+		const Matrix4& getTransform() const;
+
+		/**
+		 * @brief	Gets the inverse of the slider transform depending on 
+		 *			set position, rotation and scale values.
+		 */
+		const Matrix4& getTransformInv() const;
+
+		/**
+		 * @brief	Triggered when the slider state is changed to active.
+		 */
+		virtual void activate(const CameraPtr& camera, const Vector2I& pointerPos) { }
+
+		/**
+		 * @brief	Triggered when the slider state is changed from active to some other state.
+		 */
+		virtual void reset() { }
+
+		/**
+		 * @brief	Updates the internal transform from the stored position, rotation and scale values.
+		 */
+		void updateCachedTransform() const;
+
+		/**
+		 * @brief	Calculates amount of movement along the provided ray depending on pointer movement.
+		 *
+		 * @param	camera			Camera on which the pointer movement is occurring.
+		 * @param	position		Position of the ray to calculate movement on.
+		 * @param	direction		Direction of the ray to calculate movement on. Must be normalized.
+		 * @param	pointerStart	Starting position of the pointer when movement started, in pixels relative to provided camera.
+		 * @param	pointerEnd		Current position of the pointer, in pixels relative to provided camera.
+		 */
+		float calcDelta(const CameraPtr& camera, const Vector3& position, const Vector3& direction,
+			const Vector2I& pointerStart, const Vector2I& pointerEnd);
+
+		bool mFixedScale;
+		UINT64 mLayer;
+
+		Vector3 mPosition;
+		Quaternion mRotation;
+		Vector3 mScale;
+		float mDistanceScale;
+
+		Vector2I mStartPointerPos;
+		Vector2I mCurrentPointerPos;
+		State mState;
+
+		mutable bool mTransformDirty;
+		mutable Matrix4 mTransform;
+		mutable Matrix4 mTransformInv;
+	};
 }

+ 112 - 111
BansheeEditor/Include/BsHandleSliderDisc.h

@@ -1,112 +1,113 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsHandleSlider.h"
-#include "BsTorus.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Handle slider that returns a delta value as you drag the pointer
-	 *			along a disc. For intersection purposes the disc is internally 
-	 *			represented by a torus.
-	 */
-	class BS_ED_EXPORT HandleSliderDisc : public HandleSlider
-	{
-	public:
-		/**
-		 * @brief	Constructs a new disc slider.
-		 *
-		 * @param	normal		Normal that determines the orientation of the disc.
-		 * @param	radius		Radius of the disc.
-		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
-		 *						area in the viewport regardless of distance from camera.
-		 */
-		HandleSliderDisc(const Vector3& normal, float radius, bool fixedScale);
-		~HandleSliderDisc();
-
-		/**
-		 * @copydoc	HandleSlider::intersects
-		 */
-		bool intersects(const Ray& ray, float& t) const override;
-
-		/**
-		 * @copydoc	HandleSlider::handleInput
-		 */
-		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
-
-		/**
-		 * @brief	Enables or disables a cut-off plane that can allow the disc to be intersected
-		 *			with only in an 180 degree arc.
-		 *
-		 * @param	angle	Angle at which to start the cut-off. Points on the dist at the specified angle and the next
-		 *					180 degrees won't be interactable.	
-		 */
-		void setCutoffPlane(Degree angle, bool enabled);
-
-		/**
-		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
-		 *			along the disc. This changes every frame and will be zero unless the slider is active.
-		 */
-		Radian getDelta() const { return mDelta; }
-
-		/**
-		 * @brief	Gets the initial angle at which the drag/slide operation started. This is only
-		 *			valid when the slider is active.
-		 */
-		Radian getStartAngle() const { return mStartAngle; }
-
-	protected:
-
-		/**
-		 * @copydoc	HandleSlider::activate
-		 */
-		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override;
-
-		/**
-		 * @copydoc	HandleSlider::reset
-		 */
-		void reset() override { mDelta = 0.0f; }
-
-		/**
-		 * @brief	Calculates the closest point on an arc from a ray.
-		 *
-		 * @param	inputRay	Ray to use for determining the point.
-		 * @param	center		Center of the arc.
-		 * @param	up			Normal vector of the arc. Must be normalized.
-		 * @param	radius		Radius of the arc.
-		 * @param	startAngle	Starting angle of the arc.
-		 * @param	angleAmount	Length of the arc.
-		 *
-		 * @return	A point on the arc closest to the provided ray.
-		 */
-		Vector3 calculateClosestPointOnArc(const Ray& inputRay, const Vector3& center, const Vector3& up,
-			float radius, Degree startAngle, Degree angleAmount);
-
-		/**
-		 * @brief	Determines an angle of a point on a circle.
-		 *
-		 * @param	up		Normal vector of the circle. Must be normalized.
-		 * @param	point	Point to try to find the angle for. Caller must ensure the
-		 *					point is actually somewhere on the circle otherwise the result
-		 *					is undefined.
-		 *
-		 * @return	Angle at which the provided point lies on the circle.
-		 */
-		Degree pointOnCircleToAngle(Vector3 up, Vector3 point);
-
-		static const float TORUS_RADIUS;
-
-		Vector3 mNormal;
-		float mRadius;
-		bool mHasCutoffPlane;
-		Plane mCutoffPlane;
-
-		Vector3 mDirection;
-		Vector3 mStartPosition;
-		Degree mStartAngle;
-		Degree mDelta;
-
-		Torus mCollider;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsHandleSlider.h"
+#include "BsTorus.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Handle slider that returns a delta value as you drag the pointer
+	 *			along a disc. For intersection purposes the disc is internally 
+	 *			represented by a torus.
+	 */
+	class BS_ED_EXPORT HandleSliderDisc : public HandleSlider
+	{
+	public:
+		/**
+		 * @brief	Constructs a new disc slider.
+		 *
+		 * @param	normal		Normal that determines the orientation of the disc.
+		 * @param	radius		Radius of the disc.
+		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
+		 *						area in the viewport regardless of distance from camera.
+		 * @param	layer		Layer that allows filtering of which sliders are interacted with from a specific camera.
+		 */
+		HandleSliderDisc(const Vector3& normal, float radius, bool fixedScale, UINT64 layer);
+		~HandleSliderDisc();
+
+		/**
+		 * @copydoc	HandleSlider::intersects
+		 */
+		bool intersects(const Ray& ray, float& t) const override;
+
+		/**
+		 * @copydoc	HandleSlider::handleInput
+		 */
+		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
+
+		/**
+		 * @brief	Enables or disables a cut-off plane that can allow the disc to be intersected
+		 *			with only in an 180 degree arc.
+		 *
+		 * @param	angle	Angle at which to start the cut-off. Points on the dist at the specified angle and the next
+		 *					180 degrees won't be interactable.	
+		 */
+		void setCutoffPlane(Degree angle, bool enabled);
+
+		/**
+		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
+		 *			along the disc. This changes every frame and will be zero unless the slider is active.
+		 */
+		Radian getDelta() const { return mDelta; }
+
+		/**
+		 * @brief	Gets the initial angle at which the drag/slide operation started. This is only
+		 *			valid when the slider is active.
+		 */
+		Radian getStartAngle() const { return mStartAngle; }
+
+	protected:
+
+		/**
+		 * @copydoc	HandleSlider::activate
+		 */
+		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override;
+
+		/**
+		 * @copydoc	HandleSlider::reset
+		 */
+		void reset() override { mDelta = 0.0f; }
+
+		/**
+		 * @brief	Calculates the closest point on an arc from a ray.
+		 *
+		 * @param	inputRay	Ray to use for determining the point.
+		 * @param	center		Center of the arc.
+		 * @param	up			Normal vector of the arc. Must be normalized.
+		 * @param	radius		Radius of the arc.
+		 * @param	startAngle	Starting angle of the arc.
+		 * @param	angleAmount	Length of the arc.
+		 *
+		 * @return	A point on the arc closest to the provided ray.
+		 */
+		Vector3 calculateClosestPointOnArc(const Ray& inputRay, const Vector3& center, const Vector3& up,
+			float radius, Degree startAngle, Degree angleAmount);
+
+		/**
+		 * @brief	Determines an angle of a point on a circle.
+		 *
+		 * @param	up		Normal vector of the circle. Must be normalized.
+		 * @param	point	Point to try to find the angle for. Caller must ensure the
+		 *					point is actually somewhere on the circle otherwise the result
+		 *					is undefined.
+		 *
+		 * @return	Angle at which the provided point lies on the circle.
+		 */
+		Degree pointOnCircleToAngle(Vector3 up, Vector3 point);
+
+		static const float TORUS_RADIUS;
+
+		Vector3 mNormal;
+		float mRadius;
+		bool mHasCutoffPlane;
+		Plane mCutoffPlane;
+
+		Vector3 mDirection;
+		Vector3 mStartPosition;
+		Degree mStartAngle;
+		Degree mDelta;
+
+		Torus mCollider;
+	};
 }

+ 69 - 68
BansheeEditor/Include/BsHandleSliderLine.h

@@ -1,69 +1,70 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsHandleSlider.h"
-#include "BsCapsule.h"
-#include "BsSphere.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Handle slider that returns a delta value as you drag the pointer
-	 *			along a line. For intersection purposes the line is internally 
-	 *			by a capsule and a sphere at its cap (assuming this will be used 
-	 *			for arrow-like handles).
-	 */
-	class BS_ED_EXPORT HandleSliderLine : public HandleSlider
-	{
-	public:
-		/**
-		 * @brief	Constructs a new line slider.
-		 *
-		 * @param	direction	Direction of the line.
-		 * @param	length		Length of the slider (i.e. the line).
-		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
-		 *						area in the viewport regardless of distance from camera.
-		 */
-		HandleSliderLine(const Vector3& direction, float length, bool fixedScale);
-		~HandleSliderLine();
-
-		/**
-		 * @copydoc	HandleSlider::intersects
-		 */
-		bool intersects(const Ray& ray, float& t) const override;
-
-		/**
-		 * @copydoc	HandleSlider::handleInput
-		 */
-		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
-
-		/**
-		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
-		 *			along the line. This changes every frame and will be zero unless the slider is active.
-		 */
-		float getDelta() const { return mDelta; }
-
-	protected:
-		/**
-		 * @copydoc	HandleSlider::activate
-		 */
-		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override { mStartPosition = getPosition(); }
-
-		/**
-		 * @copydoc	HandleSlider::reset
-		 */
-		void reset() override { mDelta = 0.0f; }
-
-		static const float CAPSULE_RADIUS;
-		static const float SPHERE_RADIUS;
-
-		Vector3 mDirection;
-		float mLength;
-
-		float mDelta;
-		Vector3 mStartPosition;
-
-		Capsule mCapsuleCollider;
-		Sphere mSphereCollider;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsHandleSlider.h"
+#include "BsCapsule.h"
+#include "BsSphere.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Handle slider that returns a delta value as you drag the pointer
+	 *			along a line. For intersection purposes the line is internally 
+	 *			by a capsule and a sphere at its cap (assuming this will be used 
+	 *			for arrow-like handles).
+	 */
+	class BS_ED_EXPORT HandleSliderLine : public HandleSlider
+	{
+	public:
+		/**
+		 * @brief	Constructs a new line slider.
+		 *
+		 * @param	direction	Direction of the line.
+		 * @param	length		Length of the slider (i.e. the line).
+		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
+		 *						area in the viewport regardless of distance from camera.
+		 * @param	layer		Layer that allows filtering of which sliders are interacted with from a specific camera.
+		 */
+		HandleSliderLine(const Vector3& direction, float length, bool fixedScale, UINT64 layer);
+		~HandleSliderLine();
+
+		/**
+		 * @copydoc	HandleSlider::intersects
+		 */
+		bool intersects(const Ray& ray, float& t) const override;
+
+		/**
+		 * @copydoc	HandleSlider::handleInput
+		 */
+		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
+
+		/**
+		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
+		 *			along the line. This changes every frame and will be zero unless the slider is active.
+		 */
+		float getDelta() const { return mDelta; }
+
+	protected:
+		/**
+		 * @copydoc	HandleSlider::activate
+		 */
+		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override { mStartPosition = getPosition(); }
+
+		/**
+		 * @copydoc	HandleSlider::reset
+		 */
+		void reset() override { mDelta = 0.0f; }
+
+		static const float CAPSULE_RADIUS;
+		static const float SPHERE_RADIUS;
+
+		Vector3 mDirection;
+		float mLength;
+
+		float mDelta;
+		Vector3 mStartPosition;
+
+		Capsule mCapsuleCollider;
+		Sphere mSphereCollider;
+	};
 }

+ 79 - 78
BansheeEditor/Include/BsHandleSliderPlane.h

@@ -1,79 +1,80 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsHandleSlider.h"
-#include "BsRect3.h"
-#include "BsVector2.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Handle slider that returns a delta value as you drag the pointer
-	 *			along a plane. For intersection purposes the line is internally
-	 *			by a quadrilateral (a bounded plane).
-	 */
-	class BS_ED_EXPORT HandleSliderPlane : public HandleSlider
-	{
-	public:
-		/**
-		 * @brief	Constructs a new plane slider. The plane is constructed from two
-		 *			direction vectors.
-		 *
-		 * @param	dir1		First direction of the plane. The x component of returned delta value will be in 
-		 *						this direction. Should be perpendicular to \p dir2.
-		 * @param	dir2		Second direction of the plane. The y component of returned delta value will be in 
-		 *						this direction. Should be perpendicular to \p dir1.
-		 * @param	length		Determines size of the plane. 
-		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
-		 *						area in the viewport regardless of distance from camera.
-		 */
-		HandleSliderPlane(const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale);
-		~HandleSliderPlane();
-
-		/**
-		 * @copydoc	HandleSlider::intersects
-		 */
-		bool intersects(const Ray& ray, float& t) const override;
-
-		/**
-		 * @copydoc	HandleSlider::handleInput
-		 */
-		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
-
-		/**
-		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
-		 *			along the plane. Returned movement is in terms of the two directions originally provided
-		 *			when constructing the slider. This changes every frame and will be zero unless the slider 
-		 *			is active.
-		 */
-		Vector2 getDelta() const { return mDelta; }
-	protected:
-		/**
-		 * @copydoc	HandleSlider::activate
-		 */
-		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override;
-
-		/**
-		 * @copydoc	HandleSlider::reset
-		 */
-		void reset() override { mDelta = Vector2::ZERO; }
-
-		/**
-		 * @brief	Returns the position on plane based on pointer position.
-		 *
-		 * @param	camera		Camera we're interacting through.
-		 * @param	pointerPos	Position of the pointer in pixels relative to the provided camera's viewport.
-		 */
-		Vector3 getPositionOnPlane(const CameraPtr& camera, const Vector2I& pointerPos) const;
-
-		Vector3 mDirection1;
-		Vector3 mDirection2;
-		float mLength;
-
-		Rect3 mCollider;
-
-		Vector2 mDelta;
-		Vector3 mStartPlanePosition;
-		Vector3 mStartClickPosition;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsHandleSlider.h"
+#include "BsRect3.h"
+#include "BsVector2.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Handle slider that returns a delta value as you drag the pointer
+	 *			along a plane. For intersection purposes the line is internally
+	 *			by a quadrilateral (a bounded plane).
+	 */
+	class BS_ED_EXPORT HandleSliderPlane : public HandleSlider
+	{
+	public:
+		/**
+		 * @brief	Constructs a new plane slider. The plane is constructed from two
+		 *			direction vectors.
+		 *
+		 * @param	dir1		First direction of the plane. The x component of returned delta value will be in 
+		 *						this direction. Should be perpendicular to \p dir2.
+		 * @param	dir2		Second direction of the plane. The y component of returned delta value will be in 
+		 *						this direction. Should be perpendicular to \p dir1.
+		 * @param	length		Determines size of the plane. 
+		 * @param	fixedScale	If true the handle slider will always try to maintain the same visible
+		 *						area in the viewport regardless of distance from camera.
+		 * @param	layer		Layer that allows filtering of which sliders are interacted with from a specific camera.
+		 */
+		HandleSliderPlane(const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale, UINT64 layer);
+		~HandleSliderPlane();
+
+		/**
+		 * @copydoc	HandleSlider::intersects
+		 */
+		bool intersects(const Ray& ray, float& t) const override;
+
+		/**
+		 * @copydoc	HandleSlider::handleInput
+		 */
+		void handleInput(const CameraPtr& camera, const Vector2I& inputDelta) override;
+
+		/**
+		 * @brief	Returns a delta value that is the result of dragging/sliding the pointer 
+		 *			along the plane. Returned movement is in terms of the two directions originally provided
+		 *			when constructing the slider. This changes every frame and will be zero unless the slider 
+		 *			is active.
+		 */
+		Vector2 getDelta() const { return mDelta; }
+	protected:
+		/**
+		 * @copydoc	HandleSlider::activate
+		 */
+		void activate(const CameraPtr& camera, const Vector2I& pointerPos) override;
+
+		/**
+		 * @copydoc	HandleSlider::reset
+		 */
+		void reset() override { mDelta = Vector2::ZERO; }
+
+		/**
+		 * @brief	Returns the position on plane based on pointer position.
+		 *
+		 * @param	camera		Camera we're interacting through.
+		 * @param	pointerPos	Position of the pointer in pixels relative to the provided camera's viewport.
+		 */
+		Vector3 getPositionOnPlane(const CameraPtr& camera, const Vector2I& pointerPos) const;
+
+		Vector3 mDirection1;
+		Vector3 mDirection2;
+		float mLength;
+
+		Rect3 mCollider;
+
+		Vector2 mDelta;
+		Vector3 mStartPlanePosition;
+		Vector3 mStartClickPosition;
+	};
 }

+ 284 - 279
BansheeEditor/Source/BsHandleDrawManager.cpp

@@ -1,280 +1,285 @@
-#include "BsHandleDrawManager.h"
-#include "BsDrawHelper.h"
-#include "BsMaterial.h"
-#include "BsBuiltinEditorResources.h"
-#include "BsCoreThread.h"
-#include "BsRendererManager.h"
-#include "BsCoreRenderer.h"
-#include "BsTransientMesh.h"
-#include "BsCamera.h"
-#include "BsRendererUtility.h"
-#include "BsSceneObject.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	const UINT32 HandleDrawManager::SPHERE_QUALITY = 1;
-	const UINT32 HandleDrawManager::WIRE_SPHERE_QUALITY = 10;
-	const UINT32 HandleDrawManager::ARC_QUALITY = 10;
-
-	HandleDrawManager::HandleDrawManager()
-		:mCore(nullptr)
-	{
-		mTransform = Matrix4::IDENTITY;
-		mDrawHelper = bs_new<DrawHelper>();
-
-		HMaterial solidMaterial = BuiltinEditorResources::instance().createSolidHandleMat();
-		HMaterial wireMaterial = BuiltinEditorResources::instance().createWireHandleMat();
-
-		SPtr<MaterialCore> solidMaterialProxy = solidMaterial->getCore();
-		SPtr<MaterialCore> wireMaterialProxy = wireMaterial->getCore();
-
-		mCore.store(bs_new<HandleDrawManagerCore>(HandleDrawManagerCore::PrivatelyConstruct()), std::memory_order_release);
-
-		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::initializeCore, this, wireMaterialProxy, solidMaterialProxy));
-	}
-
-	HandleDrawManager::~HandleDrawManager()
-	{
-		bs_delete(mDrawHelper);
-
-		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::destroyCore, this, mCore.load(std::memory_order_relaxed)));
-	}
-
-	void HandleDrawManager::initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		mCore.load(std::memory_order_acquire)->initialize(wireMat, solidMat);
-	}
-
-	void HandleDrawManager::destroyCore(HandleDrawManagerCore* core)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		bs_delete(core);
-	}
-
-	void HandleDrawManager::setColor(const Color& color)
-	{
-		mDrawHelper->setColor(color);
-	}
-
-	void HandleDrawManager::setTransform(const Matrix4& transform)
-	{
-		mTransform = transform;
-	}
-
-	void HandleDrawManager::drawCube(const Vector3& position, const Vector3& extents, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->cube(position, extents);
-	}
-
-	void HandleDrawManager::drawSphere(const Vector3& position, float radius, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->sphere(position, radius);
-	}
-
-	void HandleDrawManager::drawWireCube(const Vector3& position, const Vector3& extents, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->wireCube(position, extents);
-	}
-
-	void HandleDrawManager::drawWireSphere(const Vector3& position, float radius, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->wireSphere(position, radius);
-	}
-
-	void HandleDrawManager::drawCone(const Vector3& base, const Vector3& normal, float height, float radius, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-
-		mDrawHelper->setTransform(mTransform * scale);
-		mDrawHelper->cone(base, normal, height, radius);
-	}
-
-	void HandleDrawManager::drawLine(const Vector3& start, const Vector3& end, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->line(start, end);
-	}
-
-	void HandleDrawManager::drawDisc(const Vector3& position, const Vector3& normal, float radius, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->disc(position, normal, radius);
-	}
-
-	void HandleDrawManager::drawWireDisc(const Vector3& position, const Vector3& normal, float radius, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->wireDisc(position, normal, radius);
-	}
-
-	void HandleDrawManager::drawArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->arc(position, normal, radius, startAngle, amountAngle);
-	}
-
-	void HandleDrawManager::drawWireArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->wireArc(position, normal, radius, startAngle, amountAngle);
-	}
-
-	void HandleDrawManager::drawRect(const Rect3& area, float size)
-	{
-		Matrix4 scale = Matrix4::scaling(size);
-		mDrawHelper->setTransform(mTransform * scale);
-
-		mDrawHelper->rectangle(area);
-	}
-
-	void HandleDrawManager::draw(const CameraPtr& camera)
-	{
-		mDrawHelper->clearMeshes();
-		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition());
-
-		const Vector<DrawHelper::ShapeMeshData>& meshes = mDrawHelper->getMeshes();
-		
-		Vector<HandleDrawManagerCore::MeshData> proxyData;
-		for (auto& meshData : meshes)
-		{
-			if (meshData.type == DrawHelper::MeshType::Solid)
-			{
-				proxyData.push_back(HandleDrawManagerCore::MeshData(
-					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Solid));
-			}
-			else // Wire
-			{
-				proxyData.push_back(HandleDrawManagerCore::MeshData(
-					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Wire));
-			}
-		}
-
-		HandleDrawManagerCore* core = mCore.load(std::memory_order_relaxed);
-
-		gCoreAccessor().queueCommand(std::bind(&HandleDrawManagerCore::updateData, core,
-			camera->getCore(), proxyData));
-
-		mDrawHelper->clear();
-	}
-
-	HandleDrawManagerCore::~HandleDrawManagerCore()
-	{
-		CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
-		if (mCamera != nullptr)
-			activeRenderer->_unregisterRenderCallback(mCamera.get(), 20);
-	}
-
-	void HandleDrawManagerCore::initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
-	{
-		{
-			mWireMaterial.mat = wireMat;
-			SPtr<GpuParamsCore> vertParams = wireMat->getPassParameters(0)->mVertParams;
-
-			vertParams->getParam("matViewProj", mWireMaterial.mViewProj);
-		}
-
-		{
-			mSolidMaterial.mat = solidMat;
-			SPtr<GpuParamsCore> vertParams = solidMat->getPassParameters(0)->mVertParams;
-			SPtr<GpuParamsCore> fragParams = solidMat->getPassParameters(0)->mFragParams;
-
-			vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
-			fragParams->getParam("viewDir", mSolidMaterial.mViewDir);
-		}
-	}
-
-	void HandleDrawManagerCore::updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes)
-	{
-		if (mCamera != camera)
-		{
-			CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
-			if (mCamera != nullptr)
-				activeRenderer->_unregisterRenderCallback(mCamera.get(), 20);
-
-			if (camera != nullptr)
-				activeRenderer->_registerRenderCallback(camera.get(), 20, std::bind(&HandleDrawManagerCore::render, this));
-		}
-
-		mCamera = camera;
-		mMeshes = meshes;
-	}
-
-	void HandleDrawManagerCore::render()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		if (mCamera == nullptr)
-			return;
-
-		SPtr<RenderTargetCore> renderTarget = mCamera->getViewport()->getTarget();
-
-		float width = (float)renderTarget->getProperties().getWidth();
-		float height = (float)renderTarget->getProperties().getHeight();
-
-		Rect2 normArea = mCamera->getViewport()->getNormArea();
-
-		Rect2I screenArea;
-		screenArea.x = (int)(normArea.x * width);
-		screenArea.y = (int)(normArea.y * height);
-		screenArea.width = (int)(normArea.width * width);
-		screenArea.height = (int)(normArea.height * height);
-
-		Matrix4 viewProjMat = mCamera->getProjectionMatrixRS() * mCamera->getViewMatrix();
-		mSolidMaterial.mViewProj.set(viewProjMat);
-		mSolidMaterial.mViewDir.set((Vector4)mCamera->getForward());
-		mWireMaterial.mViewProj.set(viewProjMat);
-
-		MeshType currentType = MeshType::Solid;
-		if (mMeshes.size() > 0)
-		{
-			currentType = mMeshes[0].type;
-
-			if (currentType == MeshType::Solid)
-				gRendererUtility().setPass(mSolidMaterial.mat, 0);
-			else
-				gRendererUtility().setPass(mWireMaterial.mat, 0);
-		}
-
-		for (auto& meshData : mMeshes)
-		{
-			if (currentType != meshData.type)
-			{
-				if (meshData.type == MeshType::Solid)
-					gRendererUtility().setPass(mSolidMaterial.mat, 0);
-				else
-					gRendererUtility().setPass(mWireMaterial.mat, 0);
-
-				currentType = meshData.type;
-			}
-
-			gRendererUtility().draw(meshData.mesh, meshData.mesh->getProperties().getSubMesh(0));
-		}
-	}
+#include "BsHandleDrawManager.h"
+#include "BsDrawHelper.h"
+#include "BsMaterial.h"
+#include "BsBuiltinEditorResources.h"
+#include "BsCoreThread.h"
+#include "BsRendererManager.h"
+#include "BsCoreRenderer.h"
+#include "BsTransientMesh.h"
+#include "BsCamera.h"
+#include "BsRendererUtility.h"
+#include "BsSceneObject.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	const UINT32 HandleDrawManager::SPHERE_QUALITY = 1;
+	const UINT32 HandleDrawManager::WIRE_SPHERE_QUALITY = 10;
+	const UINT32 HandleDrawManager::ARC_QUALITY = 10;
+
+	HandleDrawManager::HandleDrawManager()
+		:mCore(nullptr)
+	{
+		mTransform = Matrix4::IDENTITY;
+		mDrawHelper = bs_new<DrawHelper>();
+
+		HMaterial solidMaterial = BuiltinEditorResources::instance().createSolidHandleMat();
+		HMaterial wireMaterial = BuiltinEditorResources::instance().createWireHandleMat();
+
+		SPtr<MaterialCore> solidMaterialProxy = solidMaterial->getCore();
+		SPtr<MaterialCore> wireMaterialProxy = wireMaterial->getCore();
+
+		mCore.store(bs_new<HandleDrawManagerCore>(HandleDrawManagerCore::PrivatelyConstruct()), std::memory_order_release);
+
+		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::initializeCore, this, wireMaterialProxy, solidMaterialProxy));
+	}
+
+	HandleDrawManager::~HandleDrawManager()
+	{
+		bs_delete(mDrawHelper);
+
+		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::destroyCore, this, mCore.load(std::memory_order_relaxed)));
+	}
+
+	void HandleDrawManager::initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		mCore.load(std::memory_order_acquire)->initialize(wireMat, solidMat);
+	}
+
+	void HandleDrawManager::destroyCore(HandleDrawManagerCore* core)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		bs_delete(core);
+	}
+
+	void HandleDrawManager::setColor(const Color& color)
+	{
+		mDrawHelper->setColor(color);
+	}
+
+	void HandleDrawManager::setTransform(const Matrix4& transform)
+	{
+		mTransform = transform;
+	}
+
+	void HandleDrawManager::setLayer(UINT64 layer)
+	{
+		mDrawHelper->setLayer(layer);
+	}
+
+	void HandleDrawManager::drawCube(const Vector3& position, const Vector3& extents, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->cube(position, extents);
+	}
+
+	void HandleDrawManager::drawSphere(const Vector3& position, float radius, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->sphere(position, radius);
+	}
+
+	void HandleDrawManager::drawWireCube(const Vector3& position, const Vector3& extents, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->wireCube(position, extents);
+	}
+
+	void HandleDrawManager::drawWireSphere(const Vector3& position, float radius, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->wireSphere(position, radius);
+	}
+
+	void HandleDrawManager::drawCone(const Vector3& base, const Vector3& normal, float height, float radius, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+
+		mDrawHelper->setTransform(mTransform * scale);
+		mDrawHelper->cone(base, normal, height, radius);
+	}
+
+	void HandleDrawManager::drawLine(const Vector3& start, const Vector3& end, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->line(start, end);
+	}
+
+	void HandleDrawManager::drawDisc(const Vector3& position, const Vector3& normal, float radius, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->disc(position, normal, radius);
+	}
+
+	void HandleDrawManager::drawWireDisc(const Vector3& position, const Vector3& normal, float radius, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->wireDisc(position, normal, radius);
+	}
+
+	void HandleDrawManager::drawArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->arc(position, normal, radius, startAngle, amountAngle);
+	}
+
+	void HandleDrawManager::drawWireArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->wireArc(position, normal, radius, startAngle, amountAngle);
+	}
+
+	void HandleDrawManager::drawRect(const Rect3& area, float size)
+	{
+		Matrix4 scale = Matrix4::scaling(size);
+		mDrawHelper->setTransform(mTransform * scale);
+
+		mDrawHelper->rectangle(area);
+	}
+
+	void HandleDrawManager::draw(const CameraPtr& camera)
+	{
+		mDrawHelper->clearMeshes();
+		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition(), camera->getLayers());
+
+		const Vector<DrawHelper::ShapeMeshData>& meshes = mDrawHelper->getMeshes();
+		
+		Vector<HandleDrawManagerCore::MeshData> proxyData;
+		for (auto& meshData : meshes)
+		{
+			if (meshData.type == DrawHelper::MeshType::Solid)
+			{
+				proxyData.push_back(HandleDrawManagerCore::MeshData(
+					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Solid));
+			}
+			else // Wire
+			{
+				proxyData.push_back(HandleDrawManagerCore::MeshData(
+					meshData.mesh->getCore(), HandleDrawManagerCore::MeshType::Wire));
+			}
+		}
+
+		HandleDrawManagerCore* core = mCore.load(std::memory_order_relaxed);
+
+		gCoreAccessor().queueCommand(std::bind(&HandleDrawManagerCore::updateData, core,
+			camera->getCore(), proxyData));
+
+		mDrawHelper->clear();
+	}
+
+	HandleDrawManagerCore::~HandleDrawManagerCore()
+	{
+		CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
+		if (mCamera != nullptr)
+			activeRenderer->_unregisterRenderCallback(mCamera.get(), 20);
+	}
+
+	void HandleDrawManagerCore::initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
+	{
+		{
+			mWireMaterial.mat = wireMat;
+			SPtr<GpuParamsCore> vertParams = wireMat->getPassParameters(0)->mVertParams;
+
+			vertParams->getParam("matViewProj", mWireMaterial.mViewProj);
+		}
+
+		{
+			mSolidMaterial.mat = solidMat;
+			SPtr<GpuParamsCore> vertParams = solidMat->getPassParameters(0)->mVertParams;
+			SPtr<GpuParamsCore> fragParams = solidMat->getPassParameters(0)->mFragParams;
+
+			vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
+			fragParams->getParam("viewDir", mSolidMaterial.mViewDir);
+		}
+	}
+
+	void HandleDrawManagerCore::updateData(const SPtr<CameraCore>& camera, const Vector<MeshData>& meshes)
+	{
+		if (mCamera != camera)
+		{
+			CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
+			if (mCamera != nullptr)
+				activeRenderer->_unregisterRenderCallback(mCamera.get(), 20);
+
+			if (camera != nullptr)
+				activeRenderer->_registerRenderCallback(camera.get(), 20, std::bind(&HandleDrawManagerCore::render, this));
+		}
+
+		mCamera = camera;
+		mMeshes = meshes;
+	}
+
+	void HandleDrawManagerCore::render()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mCamera == nullptr)
+			return;
+
+		SPtr<RenderTargetCore> renderTarget = mCamera->getViewport()->getTarget();
+
+		float width = (float)renderTarget->getProperties().getWidth();
+		float height = (float)renderTarget->getProperties().getHeight();
+
+		Rect2 normArea = mCamera->getViewport()->getNormArea();
+
+		Rect2I screenArea;
+		screenArea.x = (int)(normArea.x * width);
+		screenArea.y = (int)(normArea.y * height);
+		screenArea.width = (int)(normArea.width * width);
+		screenArea.height = (int)(normArea.height * height);
+
+		Matrix4 viewProjMat = mCamera->getProjectionMatrixRS() * mCamera->getViewMatrix();
+		mSolidMaterial.mViewProj.set(viewProjMat);
+		mSolidMaterial.mViewDir.set((Vector4)mCamera->getForward());
+		mWireMaterial.mViewProj.set(viewProjMat);
+
+		MeshType currentType = MeshType::Solid;
+		if (mMeshes.size() > 0)
+		{
+			currentType = mMeshes[0].type;
+
+			if (currentType == MeshType::Solid)
+				gRendererUtility().setPass(mSolidMaterial.mat, 0);
+			else
+				gRendererUtility().setPass(mWireMaterial.mat, 0);
+		}
+
+		for (auto& meshData : mMeshes)
+		{
+			if (currentType != meshData.type)
+			{
+				if (meshData.type == MeshType::Solid)
+					gRendererUtility().setPass(mSolidMaterial.mat, 0);
+				else
+					gRendererUtility().setPass(mWireMaterial.mat, 0);
+
+				currentType = meshData.type;
+			}
+
+			gRendererUtility().draw(meshData.mesh, meshData.mesh->getProperties().getSubMesh(0));
+		}
+	}
 }

+ 124 - 124
BansheeEditor/Source/BsHandleSlider.cpp

@@ -1,125 +1,125 @@
-#include "BsHandleSlider.h"
-#include "BsCCamera.h"
-#include "BsHandleManager.h"
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	HandleSlider::HandleSlider(bool fixedScale)
-		:mFixedScale(fixedScale), mScale(Vector3::ONE), mTransformDirty(true),
-		mDistanceScale(1.0f)
-	{
-
-	}
-
-	void HandleSlider::update(const CameraPtr& camera)
-	{
-		if (mFixedScale)
-		{
-			mDistanceScale = HandleManager::instance().getHandleSize(camera, mPosition);
-			mTransformDirty = true;
-		}
-	}
-
-	void HandleSlider::setPosition(const Vector3& position)
-	{
-		mPosition = position;
-		mTransformDirty = true;
-	}
-
-	void HandleSlider::setRotation(const Quaternion& rotation)
-	{
-		mRotation = rotation;
-		mTransformDirty = true;
-	}
-
-	void HandleSlider::setScale(const Vector3& scale)
-	{
-		mScale = scale;
-		mTransformDirty = true;
-	}
-
-	const Matrix4& HandleSlider::getTransform() const
-	{
-		if (mTransformDirty)
-			updateCachedTransform();
-
-		return mTransform;
-	}
-
-	const Matrix4& HandleSlider::getTransformInv() const
-	{
-		if (mTransformDirty)
-			updateCachedTransform();
-
-		return mTransformInv;
-	}
-
-	void HandleSlider::updateCachedTransform() const
-	{
-		if (mFixedScale)
-		{
-			mTransform.setTRS(mPosition, mRotation, mScale * mDistanceScale);
-			mTransformInv.setInverseTRS(mPosition, mRotation, mScale * mDistanceScale);
-		}
-		else
-		{
-			mTransform.setTRS(mPosition, mRotation, mScale);
-			mTransformInv.setInverseTRS(mPosition, mRotation, mScale);
-		}
-
-		mTransformDirty = false;
-	}
-
-	void HandleSlider::setInactive() 
-	{ 
-		mState = State::Inactive; 
-		reset(); 
-	}
-
-	void HandleSlider::setActive(const CameraPtr& camera, const Vector2I& pointerPos)
-	{ 
-		mState = State::Active; 
-		mStartPointerPos = pointerPos; 
-		mCurrentPointerPos = pointerPos;
-		activate(camera, pointerPos);
-	}
-
-	void HandleSlider::setHover() 
-	{ 
-		mState = State::Hover; 
-		reset(); 
-	}
-
-	float HandleSlider::calcDelta(const CameraPtr& camera, const Vector3& position, const Vector3& direction,
-		const Vector2I& pointerStart, const Vector2I& pointerEnd)
-	{
-		// position + direction can sometimes project behind the camera (if the camera is looking at position
-		// from very close and at an angle), which will cause the delta to be reversed, so we compensate.
-
-		float negate = 1.0f;
-		Vector3 cameraDir = -camera->getRotation().zAxis();
-		if (cameraDir.dot((position + direction) - camera->getPosition()) <= 0.0f)
-			negate = -1.0f; // Point behind the camera
-
-		Vector2I handleStart2D = camera->worldToScreenPoint(position);
-		Vector2I handleEnd2D = camera->worldToScreenPoint(position + direction);
-
-		Vector2I handleDir2D = handleEnd2D - handleStart2D;
-
-		INT32 sqrdMag = handleDir2D.squaredLength();
-
-		if (sqrdMag == 0)
-			return 0.0f;
-
-		Vector2I diffStart = pointerStart - handleStart2D;
-		Vector2I diffEnd = pointerEnd - handleStart2D;
-
-		float mag = sqrt((float)sqrdMag);
-		float tStart = handleDir2D.dot(diffStart) / mag;
-		float tEnd = handleDir2D.dot(diffEnd) / mag;
-
-		float arbitraryScale = 1.0f / 100.0f;
-		return negate * (tEnd - tStart) * arbitraryScale;
-	}
+#include "BsHandleSlider.h"
+#include "BsCCamera.h"
+#include "BsHandleManager.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	HandleSlider::HandleSlider(bool fixedScale, UINT64 layer)
+		:mFixedScale(fixedScale), mScale(Vector3::ONE), mTransformDirty(true),
+		mDistanceScale(1.0f), mLayer(layer)
+	{
+
+	}
+
+	void HandleSlider::update(const CameraPtr& camera)
+	{
+		if (mFixedScale)
+		{
+			mDistanceScale = HandleManager::instance().getHandleSize(camera, mPosition);
+			mTransformDirty = true;
+		}
+	}
+
+	void HandleSlider::setPosition(const Vector3& position)
+	{
+		mPosition = position;
+		mTransformDirty = true;
+	}
+
+	void HandleSlider::setRotation(const Quaternion& rotation)
+	{
+		mRotation = rotation;
+		mTransformDirty = true;
+	}
+
+	void HandleSlider::setScale(const Vector3& scale)
+	{
+		mScale = scale;
+		mTransformDirty = true;
+	}
+
+	const Matrix4& HandleSlider::getTransform() const
+	{
+		if (mTransformDirty)
+			updateCachedTransform();
+
+		return mTransform;
+	}
+
+	const Matrix4& HandleSlider::getTransformInv() const
+	{
+		if (mTransformDirty)
+			updateCachedTransform();
+
+		return mTransformInv;
+	}
+
+	void HandleSlider::updateCachedTransform() const
+	{
+		if (mFixedScale)
+		{
+			mTransform.setTRS(mPosition, mRotation, mScale * mDistanceScale);
+			mTransformInv.setInverseTRS(mPosition, mRotation, mScale * mDistanceScale);
+		}
+		else
+		{
+			mTransform.setTRS(mPosition, mRotation, mScale);
+			mTransformInv.setInverseTRS(mPosition, mRotation, mScale);
+		}
+
+		mTransformDirty = false;
+	}
+
+	void HandleSlider::setInactive() 
+	{ 
+		mState = State::Inactive; 
+		reset(); 
+	}
+
+	void HandleSlider::setActive(const CameraPtr& camera, const Vector2I& pointerPos)
+	{ 
+		mState = State::Active; 
+		mStartPointerPos = pointerPos; 
+		mCurrentPointerPos = pointerPos;
+		activate(camera, pointerPos);
+	}
+
+	void HandleSlider::setHover() 
+	{ 
+		mState = State::Hover; 
+		reset(); 
+	}
+
+	float HandleSlider::calcDelta(const CameraPtr& camera, const Vector3& position, const Vector3& direction,
+		const Vector2I& pointerStart, const Vector2I& pointerEnd)
+	{
+		// position + direction can sometimes project behind the camera (if the camera is looking at position
+		// from very close and at an angle), which will cause the delta to be reversed, so we compensate.
+
+		float negate = 1.0f;
+		Vector3 cameraDir = -camera->getRotation().zAxis();
+		if (cameraDir.dot((position + direction) - camera->getPosition()) <= 0.0f)
+			negate = -1.0f; // Point behind the camera
+
+		Vector2I handleStart2D = camera->worldToScreenPoint(position);
+		Vector2I handleEnd2D = camera->worldToScreenPoint(position + direction);
+
+		Vector2I handleDir2D = handleEnd2D - handleStart2D;
+
+		INT32 sqrdMag = handleDir2D.squaredLength();
+
+		if (sqrdMag == 0)
+			return 0.0f;
+
+		Vector2I diffStart = pointerStart - handleStart2D;
+		Vector2I diffEnd = pointerEnd - handleStart2D;
+
+		float mag = sqrt((float)sqrdMag);
+		float tStart = handleDir2D.dot(diffStart) / mag;
+		float tEnd = handleDir2D.dot(diffEnd) / mag;
+
+		float arbitraryScale = 1.0f / 100.0f;
+		return negate * (tEnd - tStart) * arbitraryScale;
+	}
 }

+ 182 - 182
BansheeEditor/Source/BsHandleSliderDisc.cpp

@@ -1,183 +1,183 @@
-#include "BsHandleSliderDisc.h"
-#include "BsHandleManager.h"
-#include "BsHandleSliderManager.h"
-#include "BsRay.h"
-#include "BsVector3.h"
-#include "BsQuaternion.h"
-#include "BsCCamera.h"
-
-// DEBUG ONLY
-#include "BsDebug.h"
-#include "BsGizmoManager.h"
-
-namespace BansheeEngine
-{
-	const float HandleSliderDisc::TORUS_RADIUS = 0.1f;
-
-	HandleSliderDisc::HandleSliderDisc(const Vector3& normal, float radius, bool fixedScale)
-		:HandleSlider(fixedScale), mRadius(radius), mNormal(normal), mDelta(0.0f), mHasCutoffPlane(false)
-	{
-		mCollider = Torus(normal, radius, TORUS_RADIUS);
-
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._registerSlider(this);
-	}
-
-	HandleSliderDisc::~HandleSliderDisc()
-	{
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._unregisterSlider(this);
-	}
-
-	void HandleSliderDisc::setCutoffPlane(Degree angle, bool enabled)
-	{
-		mHasCutoffPlane = enabled;
-
-		if (mHasCutoffPlane)
-		{
-			Vector3 up = mNormal;
-
-			Quaternion alignWithStart = Quaternion(-Vector3::UNIT_Y, angle);
-			Quaternion alignWithUp = Quaternion::getRotationFromTo(Vector3::UNIT_Y, up);
-
-			Vector3 right = alignWithUp.rotate(alignWithStart.rotate(Vector3::UNIT_X));
-			right.normalize();
-
-			Vector3 planeNormal = right.cross(up);
-
-			mCutoffPlane = Plane(planeNormal, 0.0f);
-		}
-	}
-
-	bool HandleSliderDisc::intersects(const Ray& ray, float& t) const
-	{
-		Ray localRay = ray;
-		localRay.transform(getTransformInv());
-
-		auto intersect = mCollider.intersects(localRay);
-		if (intersect.first)
-		{
-			t = intersect.second;
-
-			if (mHasCutoffPlane)
-			{
-				auto cutoffIntersect = mCutoffPlane.intersects(localRay);
-				if (cutoffIntersect.first && cutoffIntersect.second < t)
-					return false;
-			}
-
-			return true;
-		}
-
-		return false;
-	}
-
-	Vector3 HandleSliderDisc::calculateClosestPointOnArc(const Ray& inputRay, const Vector3& center, const Vector3& up,
-		float radius, Degree startAngle, Degree angleAmount)
-	{
-		Vector3 arcBasis[3];
-		arcBasis[1] = up;
-		arcBasis[1].orthogonalComplement(arcBasis[2], arcBasis[0]);
-
-		Matrix4 worldToPlane = Matrix4::IDENTITY;
-		worldToPlane.setColumn(0, (Vector4)arcBasis[0]);
-		worldToPlane.setColumn(1, (Vector4)arcBasis[1]);
-		worldToPlane.setColumn(2, (Vector4)arcBasis[2]);
-		worldToPlane.setColumn(3, (Vector4)worldToPlane.multiplyAffine(-center));
-		worldToPlane[3][3] = 1;
-
-		Plane plane(up, (-center).dot(up));
-		Vector3 pointOnPlane;
-
-		auto intersectResult = plane.intersects(inputRay);
-
-		float t = 0.0f;
-		if (intersectResult.first)
-			pointOnPlane = inputRay.getPoint(intersectResult.second);
-		else
-			pointOnPlane = Vector3::ZERO;
-
-		pointOnPlane = worldToPlane.multiplyAffine(pointOnPlane);
-		Vector2 pointOnPlane2D(pointOnPlane.x, pointOnPlane.z); // y always 0
-
-		Vector2 closestPoint2D;
-		float dist = pointOnPlane2D.length();
-		if (dist > 0.0f)
-			closestPoint2D = mRadius * (pointOnPlane2D / dist);
-		else
-			closestPoint2D = Vector2(mRadius, 0);
-
-		Radian angle = Math::atan2(-closestPoint2D.y, -closestPoint2D.x) + Math::PI;
-
-		float angleRad = angle.valueRadians();
-		float angleAmountRad = Math::clamp(angleAmount.valueRadians(), 0.0f, Math::PI * 2);
-
-		float startAngleRad = startAngle.wrap().valueRadians();
-		float endAngleRad = startAngleRad + angleAmountRad;
-
-		float clampedAngle = angleRad;
-		if (endAngleRad <= Math::PI * 2)
-		{
-			clampedAngle = Math::clamp(angleRad, startAngleRad, endAngleRad);
-		}
-		else
-		{
-			if (angleRad >= startAngleRad)
-				clampedAngle = Math::clamp(angleRad, startAngleRad, Math::PI * 2);
-			else
-			{
-				endAngleRad -= Math::PI * 2;
-				if (angleRad > endAngleRad)
-				{
-					if ((startAngleRad - angleRad) > (angleRad - endAngleRad))
-						clampedAngle = endAngleRad;
-					else
-						clampedAngle = startAngleRad;
-				}
-				else
-					clampedAngle = angleRad;
-			}
-		}
-
-		Vector3 clampedAnglePoint;
-		clampedAnglePoint.x = Math::cos(clampedAngle) * radius;
-		clampedAnglePoint.z = Math::sin(clampedAngle) * radius;
-
-		return worldToPlane.inverseAffine().multiplyAffine(clampedAnglePoint);
-	}
-
-	Degree HandleSliderDisc::pointOnCircleToAngle(Vector3 up, Vector3 point)
-	{
-		Quaternion rot = Quaternion::getRotationFromTo(up, Vector3::UNIT_Y);
-
-		Matrix4 worldToPlane = Matrix4::TRS(Vector3::ZERO, rot, Vector3::ONE);
-		point = worldToPlane.multiplyAffine(point);
-
-		return Radian(Math::atan2(-point.z, -point.x) + Math::PI);
-	}
-
-	void HandleSliderDisc::activate(const CameraPtr& camera, const Vector2I& pointerPos)
-	{
-		Ray localRay = camera->screenPointToRay(pointerPos);
-		localRay.transformAffine(getTransformInv());
-
-		mStartPosition = calculateClosestPointOnArc(localRay, Vector3::ZERO, mNormal, mRadius, Degree(0.0f), Degree(360.0f));
-		mStartAngle = pointOnCircleToAngle(mNormal, mStartPosition);
-		mStartPosition = getTransform().multiplyAffine(mStartPosition);
-
-		Vector3 worldNormal = getTransform().multiplyDirection(mNormal);
-		worldNormal.normalize();
-
-		Vector3 toStart = mStartPosition - getPosition();
-		mDirection = worldNormal.cross(toStart);
-		mDirection.normalize();
-	}
-
-	void HandleSliderDisc::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
-	{
-		assert(getState() == State::Active);
-
-		mCurrentPointerPos += inputDelta;
-		mDelta = calcDelta(camera, mStartPosition, mDirection, mStartPointerPos, mCurrentPointerPos) * Math::RAD2DEG;
-	}
+#include "BsHandleSliderDisc.h"
+#include "BsHandleManager.h"
+#include "BsHandleSliderManager.h"
+#include "BsRay.h"
+#include "BsVector3.h"
+#include "BsQuaternion.h"
+#include "BsCCamera.h"
+
+// DEBUG ONLY
+#include "BsDebug.h"
+#include "BsGizmoManager.h"
+
+namespace BansheeEngine
+{
+	const float HandleSliderDisc::TORUS_RADIUS = 0.1f;
+
+	HandleSliderDisc::HandleSliderDisc(const Vector3& normal, float radius, bool fixedScale, UINT64 layer)
+		:HandleSlider(fixedScale, layer), mRadius(radius), mNormal(normal), mDelta(0.0f), mHasCutoffPlane(false)
+	{
+		mCollider = Torus(normal, radius, TORUS_RADIUS);
+
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._registerSlider(this);
+	}
+
+	HandleSliderDisc::~HandleSliderDisc()
+	{
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._unregisterSlider(this);
+	}
+
+	void HandleSliderDisc::setCutoffPlane(Degree angle, bool enabled)
+	{
+		mHasCutoffPlane = enabled;
+
+		if (mHasCutoffPlane)
+		{
+			Vector3 up = mNormal;
+
+			Quaternion alignWithStart = Quaternion(-Vector3::UNIT_Y, angle);
+			Quaternion alignWithUp = Quaternion::getRotationFromTo(Vector3::UNIT_Y, up);
+
+			Vector3 right = alignWithUp.rotate(alignWithStart.rotate(Vector3::UNIT_X));
+			right.normalize();
+
+			Vector3 planeNormal = right.cross(up);
+
+			mCutoffPlane = Plane(planeNormal, 0.0f);
+		}
+	}
+
+	bool HandleSliderDisc::intersects(const Ray& ray, float& t) const
+	{
+		Ray localRay = ray;
+		localRay.transform(getTransformInv());
+
+		auto intersect = mCollider.intersects(localRay);
+		if (intersect.first)
+		{
+			t = intersect.second;
+
+			if (mHasCutoffPlane)
+			{
+				auto cutoffIntersect = mCutoffPlane.intersects(localRay);
+				if (cutoffIntersect.first && cutoffIntersect.second < t)
+					return false;
+			}
+
+			return true;
+		}
+
+		return false;
+	}
+
+	Vector3 HandleSliderDisc::calculateClosestPointOnArc(const Ray& inputRay, const Vector3& center, const Vector3& up,
+		float radius, Degree startAngle, Degree angleAmount)
+	{
+		Vector3 arcBasis[3];
+		arcBasis[1] = up;
+		arcBasis[1].orthogonalComplement(arcBasis[2], arcBasis[0]);
+
+		Matrix4 worldToPlane = Matrix4::IDENTITY;
+		worldToPlane.setColumn(0, (Vector4)arcBasis[0]);
+		worldToPlane.setColumn(1, (Vector4)arcBasis[1]);
+		worldToPlane.setColumn(2, (Vector4)arcBasis[2]);
+		worldToPlane.setColumn(3, (Vector4)worldToPlane.multiplyAffine(-center));
+		worldToPlane[3][3] = 1;
+
+		Plane plane(up, (-center).dot(up));
+		Vector3 pointOnPlane;
+
+		auto intersectResult = plane.intersects(inputRay);
+
+		float t = 0.0f;
+		if (intersectResult.first)
+			pointOnPlane = inputRay.getPoint(intersectResult.second);
+		else
+			pointOnPlane = Vector3::ZERO;
+
+		pointOnPlane = worldToPlane.multiplyAffine(pointOnPlane);
+		Vector2 pointOnPlane2D(pointOnPlane.x, pointOnPlane.z); // y always 0
+
+		Vector2 closestPoint2D;
+		float dist = pointOnPlane2D.length();
+		if (dist > 0.0f)
+			closestPoint2D = mRadius * (pointOnPlane2D / dist);
+		else
+			closestPoint2D = Vector2(mRadius, 0);
+
+		Radian angle = Math::atan2(-closestPoint2D.y, -closestPoint2D.x) + Math::PI;
+
+		float angleRad = angle.valueRadians();
+		float angleAmountRad = Math::clamp(angleAmount.valueRadians(), 0.0f, Math::PI * 2);
+
+		float startAngleRad = startAngle.wrap().valueRadians();
+		float endAngleRad = startAngleRad + angleAmountRad;
+
+		float clampedAngle = angleRad;
+		if (endAngleRad <= Math::PI * 2)
+		{
+			clampedAngle = Math::clamp(angleRad, startAngleRad, endAngleRad);
+		}
+		else
+		{
+			if (angleRad >= startAngleRad)
+				clampedAngle = Math::clamp(angleRad, startAngleRad, Math::PI * 2);
+			else
+			{
+				endAngleRad -= Math::PI * 2;
+				if (angleRad > endAngleRad)
+				{
+					if ((startAngleRad - angleRad) > (angleRad - endAngleRad))
+						clampedAngle = endAngleRad;
+					else
+						clampedAngle = startAngleRad;
+				}
+				else
+					clampedAngle = angleRad;
+			}
+		}
+
+		Vector3 clampedAnglePoint;
+		clampedAnglePoint.x = Math::cos(clampedAngle) * radius;
+		clampedAnglePoint.z = Math::sin(clampedAngle) * radius;
+
+		return worldToPlane.inverseAffine().multiplyAffine(clampedAnglePoint);
+	}
+
+	Degree HandleSliderDisc::pointOnCircleToAngle(Vector3 up, Vector3 point)
+	{
+		Quaternion rot = Quaternion::getRotationFromTo(up, Vector3::UNIT_Y);
+
+		Matrix4 worldToPlane = Matrix4::TRS(Vector3::ZERO, rot, Vector3::ONE);
+		point = worldToPlane.multiplyAffine(point);
+
+		return Radian(Math::atan2(-point.z, -point.x) + Math::PI);
+	}
+
+	void HandleSliderDisc::activate(const CameraPtr& camera, const Vector2I& pointerPos)
+	{
+		Ray localRay = camera->screenPointToRay(pointerPos);
+		localRay.transformAffine(getTransformInv());
+
+		mStartPosition = calculateClosestPointOnArc(localRay, Vector3::ZERO, mNormal, mRadius, Degree(0.0f), Degree(360.0f));
+		mStartAngle = pointOnCircleToAngle(mNormal, mStartPosition);
+		mStartPosition = getTransform().multiplyAffine(mStartPosition);
+
+		Vector3 worldNormal = getTransform().multiplyDirection(mNormal);
+		worldNormal.normalize();
+
+		Vector3 toStart = mStartPosition - getPosition();
+		mDirection = worldNormal.cross(toStart);
+		mDirection.normalize();
+	}
+
+	void HandleSliderDisc::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
+	{
+		assert(getState() == State::Active);
+
+		mCurrentPointerPos += inputDelta;
+		mDelta = calcDelta(camera, mStartPosition, mDirection, mStartPointerPos, mCurrentPointerPos) * Math::RAD2DEG;
+	}
 }

+ 83 - 83
BansheeEditor/Source/BsHandleSliderLine.cpp

@@ -1,84 +1,84 @@
-#include "BsHandleSliderLine.h"
-#include "BsHandleManager.h"
-#include "BsHandleSliderManager.h"
-#include "BsCapsule.h"
-#include "BsLineSegment3.h"
-#include "BsSphere.h"
-#include "BsRay.h"
-
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	const float HandleSliderLine::CAPSULE_RADIUS = 0.05f;
-	const float HandleSliderLine::SPHERE_RADIUS = 0.2f;
-
-	HandleSliderLine::HandleSliderLine(const Vector3& direction, float length, bool fixedScale)
-		:HandleSlider(fixedScale), mLength(length), mDelta(0.0f)
-	{
-		mDirection = Vector3::normalize(direction);
-
-		Vector3 start = Vector3::ZERO;
-		Vector3 end = start + mDirection * length;
-
-		Vector3 sphereCenter = start + mDirection * std::max(0.0f, length - SPHERE_RADIUS);
-
-		mCapsuleCollider = Capsule(LineSegment3(start, end), CAPSULE_RADIUS);
-		mSphereCollider = Sphere(sphereCenter, SPHERE_RADIUS);
-
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._registerSlider(this);
-	}
-
-	HandleSliderLine::~HandleSliderLine()
-	{
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._unregisterSlider(this);
-	}
-
-	bool HandleSliderLine::intersects(const Ray& ray, float& t) const
-	{
-		Ray localRay = ray;
-		localRay.transformAffine(getTransformInv());
-
-		auto capsuleIntersect = mCapsuleCollider.intersects(localRay);
-		auto sphereIntersect = mSphereCollider.intersects(localRay);
-
-		t = std::numeric_limits<float>::max();
-		bool gotIntersect = false;
-
-		if (capsuleIntersect.first)
-		{
-			t = capsuleIntersect.second;
-			gotIntersect = true;
-		}
-
-		if (sphereIntersect.first)
-		{
-			if (sphereIntersect.second < t)
-			{
-				t = sphereIntersect.second;
-				gotIntersect = true;
-			}
-		}
-
-		if (gotIntersect)
-		{
-			Vector3 intrPoint = localRay.getPoint(t);
-			intrPoint = getTransform().multiplyAffine(intrPoint);
-			t = (intrPoint - ray.getOrigin()).length(); // Get distance in world space
-		}
-
-		return gotIntersect;
-	}
-
-	void HandleSliderLine::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
-	{
-		assert(getState() == State::Active);
-
-		mCurrentPointerPos += inputDelta;
-
-		Vector3 worldDir = getRotation().rotate(mDirection);
-		mDelta = calcDelta(camera, mStartPosition, worldDir, mStartPointerPos, mCurrentPointerPos);
-	}
+#include "BsHandleSliderLine.h"
+#include "BsHandleManager.h"
+#include "BsHandleSliderManager.h"
+#include "BsCapsule.h"
+#include "BsLineSegment3.h"
+#include "BsSphere.h"
+#include "BsRay.h"
+
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	const float HandleSliderLine::CAPSULE_RADIUS = 0.05f;
+	const float HandleSliderLine::SPHERE_RADIUS = 0.2f;
+
+	HandleSliderLine::HandleSliderLine(const Vector3& direction, float length, bool fixedScale, UINT64 layer)
+		:HandleSlider(fixedScale, layer), mLength(length), mDelta(0.0f)
+	{
+		mDirection = Vector3::normalize(direction);
+
+		Vector3 start = Vector3::ZERO;
+		Vector3 end = start + mDirection * length;
+
+		Vector3 sphereCenter = start + mDirection * std::max(0.0f, length - SPHERE_RADIUS);
+
+		mCapsuleCollider = Capsule(LineSegment3(start, end), CAPSULE_RADIUS);
+		mSphereCollider = Sphere(sphereCenter, SPHERE_RADIUS);
+
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._registerSlider(this);
+	}
+
+	HandleSliderLine::~HandleSliderLine()
+	{
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._unregisterSlider(this);
+	}
+
+	bool HandleSliderLine::intersects(const Ray& ray, float& t) const
+	{
+		Ray localRay = ray;
+		localRay.transformAffine(getTransformInv());
+
+		auto capsuleIntersect = mCapsuleCollider.intersects(localRay);
+		auto sphereIntersect = mSphereCollider.intersects(localRay);
+
+		t = std::numeric_limits<float>::max();
+		bool gotIntersect = false;
+
+		if (capsuleIntersect.first)
+		{
+			t = capsuleIntersect.second;
+			gotIntersect = true;
+		}
+
+		if (sphereIntersect.first)
+		{
+			if (sphereIntersect.second < t)
+			{
+				t = sphereIntersect.second;
+				gotIntersect = true;
+			}
+		}
+
+		if (gotIntersect)
+		{
+			Vector3 intrPoint = localRay.getPoint(t);
+			intrPoint = getTransform().multiplyAffine(intrPoint);
+			t = (intrPoint - ray.getOrigin()).length(); // Get distance in world space
+		}
+
+		return gotIntersect;
+	}
+
+	void HandleSliderLine::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
+	{
+		assert(getState() == State::Active);
+
+		mCurrentPointerPos += inputDelta;
+
+		Vector3 worldDir = getRotation().rotate(mDirection);
+		mDelta = calcDelta(camera, mStartPosition, worldDir, mStartPointerPos, mCurrentPointerPos);
+	}
 }

+ 131 - 129
BansheeEditor/Source/BsHandleSliderManager.cpp

@@ -1,130 +1,132 @@
-#include "BsHandleSliderManager.h"
-#include "BsDrawHelper.h"
-#include "BsMaterial.h"
-#include "BsBuiltinEditorResources.h"
-#include "BsCoreThread.h"
-#include "BsRendererManager.h"
-#include "BsCoreRenderer.h"
-#include "BsTransientMesh.h"
-#include "BsCCamera.h"
-#include "BsHandleSlider.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	HandleSliderManager::HandleSliderManager()
-		:mActiveSlider(nullptr), mHoverSlider(nullptr)
-	{
-
-	}
-
-	HandleSliderManager::~HandleSliderManager()
-	{
-
-	}
-
-	void HandleSliderManager::update(const CameraPtr& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
-	{
-		for (auto& slider : mSliders)
-			slider->update(camera);
-
-		if (mActiveSlider != nullptr)
-		{
-			mActiveSlider->handleInput(camera, inputDelta);
-		}
-		else
-		{
-			HandleSlider* newHoverSlider = findUnderCursor(camera, inputPos);
-
-			if (newHoverSlider != mHoverSlider)
-			{
-				if (mHoverSlider != nullptr)
-				{
-					mHoverSlider->setInactive();
-					mHoverSlider = nullptr;
-				}
-
-				if (newHoverSlider != nullptr)
-				{
-					mHoverSlider = newHoverSlider;
-					mHoverSlider->setHover();
-				}
-			}
-		}
-	}
-
-	void HandleSliderManager::trySelect(const CameraPtr& camera, const Vector2I& inputPos)
-	{
-		HandleSlider* newActiveSlider = findUnderCursor(camera, inputPos);
-
-		if (mHoverSlider != nullptr)
-		{
-			mHoverSlider->setInactive();
-			mHoverSlider = nullptr;
-		}
-
-		if (newActiveSlider != mActiveSlider)
-		{
-			if (mActiveSlider != nullptr)
-			{
-				mActiveSlider->setInactive();
-				mActiveSlider = nullptr;
-			}
-
-			if (newActiveSlider != nullptr)
-			{
-				mActiveSlider = newActiveSlider;
-				mActiveSlider->setActive(camera, inputPos);
-			}
-		}
-	}
-
-	void HandleSliderManager::clearSelection()
-	{
-		if (mActiveSlider != nullptr)
-		{
-			mActiveSlider->setInactive();
-			mActiveSlider = nullptr;
-		}
-	}
-
-	HandleSlider* HandleSliderManager::findUnderCursor(const CameraPtr& camera, const Vector2I& inputPos) const
-	{
-		Ray inputRay = camera->screenPointToRay(inputPos);
-
-		float nearestT = std::numeric_limits<float>::max();
-		HandleSlider* overSlider = nullptr;
-		
-		for (auto& slider : mSliders)
-		{
-			float t;
-			if (slider->intersects(inputRay, t))
-			{
-				if (t < nearestT)
-				{
-					overSlider = slider;
-					nearestT = t;
-				}
-			}
-		}
-
-		return overSlider;
-	}
-
-	void HandleSliderManager::_registerSlider(HandleSlider* slider)
-	{
-		mSliders.insert(slider);
-	}
-
-	void HandleSliderManager::_unregisterSlider(HandleSlider* slider)
-	{
-		mSliders.erase(slider);
-
-		if (mActiveSlider == slider)
-			mActiveSlider = nullptr;
-
-		if (mHoverSlider == slider)
-			mHoverSlider = nullptr;
-	}
+#include "BsHandleSliderManager.h"
+#include "BsDrawHelper.h"
+#include "BsMaterial.h"
+#include "BsBuiltinEditorResources.h"
+#include "BsCoreThread.h"
+#include "BsRendererManager.h"
+#include "BsCoreRenderer.h"
+#include "BsTransientMesh.h"
+#include "BsCCamera.h"
+#include "BsHandleSlider.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	HandleSliderManager::HandleSliderManager()
+		:mActiveSlider(nullptr), mHoverSlider(nullptr)
+	{
+
+	}
+
+	HandleSliderManager::~HandleSliderManager()
+	{
+
+	}
+
+	void HandleSliderManager::update(const CameraPtr& camera, const Vector2I& inputPos, const Vector2I& inputDelta)
+	{
+		for (auto& slider : mSliders)
+			slider->update(camera);
+
+		if (mActiveSlider != nullptr)
+		{
+			mActiveSlider->handleInput(camera, inputDelta);
+		}
+		else
+		{
+			HandleSlider* newHoverSlider = findUnderCursor(camera, inputPos);
+
+			if (newHoverSlider != mHoverSlider)
+			{
+				if (mHoverSlider != nullptr)
+				{
+					mHoverSlider->setInactive();
+					mHoverSlider = nullptr;
+				}
+
+				if (newHoverSlider != nullptr)
+				{
+					mHoverSlider = newHoverSlider;
+					mHoverSlider->setHover();
+				}
+			}
+		}
+	}
+
+	void HandleSliderManager::trySelect(const CameraPtr& camera, const Vector2I& inputPos)
+	{
+		HandleSlider* newActiveSlider = findUnderCursor(camera, inputPos);
+
+		if (mHoverSlider != nullptr)
+		{
+			mHoverSlider->setInactive();
+			mHoverSlider = nullptr;
+		}
+
+		if (newActiveSlider != mActiveSlider)
+		{
+			if (mActiveSlider != nullptr)
+			{
+				mActiveSlider->setInactive();
+				mActiveSlider = nullptr;
+			}
+
+			if (newActiveSlider != nullptr)
+			{
+				mActiveSlider = newActiveSlider;
+				mActiveSlider->setActive(camera, inputPos);
+			}
+		}
+	}
+
+	void HandleSliderManager::clearSelection()
+	{
+		if (mActiveSlider != nullptr)
+		{
+			mActiveSlider->setInactive();
+			mActiveSlider = nullptr;
+		}
+	}
+
+	HandleSlider* HandleSliderManager::findUnderCursor(const CameraPtr& camera, const Vector2I& inputPos) const
+	{
+		Ray inputRay = camera->screenPointToRay(inputPos);
+
+		float nearestT = std::numeric_limits<float>::max();
+		HandleSlider* overSlider = nullptr;
+		
+		for (auto& slider : mSliders)
+		{
+			bool layerMatches = (camera->getLayers() & slider->getLayer()) != 0;
+
+			float t;
+			if (layerMatches && slider->intersects(inputRay, t))
+			{
+				if (t < nearestT)
+				{
+					overSlider = slider;
+					nearestT = t;
+				}
+			}
+		}
+
+		return overSlider;
+	}
+
+	void HandleSliderManager::_registerSlider(HandleSlider* slider)
+	{
+		mSliders.insert(slider);
+	}
+
+	void HandleSliderManager::_unregisterSlider(HandleSlider* slider)
+	{
+		mSliders.erase(slider);
+
+		if (mActiveSlider == slider)
+			mActiveSlider = nullptr;
+
+		if (mHoverSlider == slider)
+			mHoverSlider = nullptr;
+	}
 }

+ 91 - 91
BansheeEditor/Source/BsHandleSliderPlane.cpp

@@ -1,92 +1,92 @@
-#include "BsHandleSliderPlane.h"
-#include "BsHandleManager.h"
-#include "BsHandleSliderManager.h"
-#include "BsVector3.h"
-#include "BsRay.h"
-#include "BsPlane.h"
-#include "BsCamera.h"
-
-namespace BansheeEngine
-{
-	HandleSliderPlane::HandleSliderPlane(const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale)
-		:HandleSlider(fixedScale), mLength(length)
-	{
-		mDirection1 = Vector3::normalize(dir1);
-		mDirection2 = Vector3::normalize(dir2);
-
-		float halfLength = length * 0.5f;
-		std::array<Vector3, 2> axes = { mDirection1, mDirection2 };
-		std::array<float, 2> extents = { halfLength, halfLength };
-
-		Vector3 center = (dir1 * length + dir2 * length) * 0.5f;
-		mCollider = Rect3(center, axes, extents);
-
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._registerSlider(this);
-	}
-
-	HandleSliderPlane::~HandleSliderPlane()
-	{
-		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
-		sliderManager._unregisterSlider(this);
-	}
-
-	bool HandleSliderPlane::intersects(const Ray& ray, float& t) const
-	{
-		Ray localRay = ray;
-		localRay.transform(getTransformInv());
-
-		auto intersect = mCollider.intersects(localRay);
-
-		if (intersect.first)
-		{
-			t = intersect.second;
-
-			return true;
-		}
-
-		return false;
-	}
-
-	void HandleSliderPlane::activate(const CameraPtr& camera, const Vector2I& pointerPos)
-	{
-		mStartPlanePosition = getPosition();
-		mStartClickPosition = getPositionOnPlane(camera, pointerPos);
-	}
-
-	void HandleSliderPlane::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
-	{
-		assert(getState() == State::Active);
-
-		mCurrentPointerPos += inputDelta;
-
-		Vector3 worldDir1 = getRotation().rotate(mDirection1);
-		Vector3 worldDir2 = getRotation().rotate(mDirection2);
-
-		Vector3 intersectPosition = getPositionOnPlane(camera, mCurrentPointerPos);
-		Vector3 positionDelta = intersectPosition - mStartClickPosition;
-
-		mDelta.x = positionDelta.dot(worldDir1);
-		mDelta.y = positionDelta.dot(worldDir2);
-	}
-
-	Vector3 HandleSliderPlane::getPositionOnPlane(const CameraPtr& camera, const Vector2I& pointerPos) const
-	{
-		Vector3 worldDir1 = getRotation().rotate(mDirection1);
-		Vector3 worldDir2 = getRotation().rotate(mDirection2);
-
-		Vector3 normal = worldDir1.cross(worldDir2);
-		float dot = normal.dot(camera->getForward());
-		if (dot > 0)
-			normal = -normal;
-
-		Plane plane(normal, mStartPlanePosition);
-
-		Ray clickRay = camera->screenPointToRay(pointerPos);
-		auto intersectResult = plane.intersects(clickRay);
-		if (intersectResult.first)
-			return clickRay.getPoint(intersectResult.second);
-
-		return mStartClickPosition;
-	}
+#include "BsHandleSliderPlane.h"
+#include "BsHandleManager.h"
+#include "BsHandleSliderManager.h"
+#include "BsVector3.h"
+#include "BsRay.h"
+#include "BsPlane.h"
+#include "BsCamera.h"
+
+namespace BansheeEngine
+{
+	HandleSliderPlane::HandleSliderPlane(const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale, UINT64 layer)
+		:HandleSlider(fixedScale, layer), mLength(length)
+	{
+		mDirection1 = Vector3::normalize(dir1);
+		mDirection2 = Vector3::normalize(dir2);
+
+		float halfLength = length * 0.5f;
+		std::array<Vector3, 2> axes = { mDirection1, mDirection2 };
+		std::array<float, 2> extents = { halfLength, halfLength };
+
+		Vector3 center = (dir1 * length + dir2 * length) * 0.5f;
+		mCollider = Rect3(center, axes, extents);
+
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._registerSlider(this);
+	}
+
+	HandleSliderPlane::~HandleSliderPlane()
+	{
+		HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
+		sliderManager._unregisterSlider(this);
+	}
+
+	bool HandleSliderPlane::intersects(const Ray& ray, float& t) const
+	{
+		Ray localRay = ray;
+		localRay.transform(getTransformInv());
+
+		auto intersect = mCollider.intersects(localRay);
+
+		if (intersect.first)
+		{
+			t = intersect.second;
+
+			return true;
+		}
+
+		return false;
+	}
+
+	void HandleSliderPlane::activate(const CameraPtr& camera, const Vector2I& pointerPos)
+	{
+		mStartPlanePosition = getPosition();
+		mStartClickPosition = getPositionOnPlane(camera, pointerPos);
+	}
+
+	void HandleSliderPlane::handleInput(const CameraPtr& camera, const Vector2I& inputDelta)
+	{
+		assert(getState() == State::Active);
+
+		mCurrentPointerPos += inputDelta;
+
+		Vector3 worldDir1 = getRotation().rotate(mDirection1);
+		Vector3 worldDir2 = getRotation().rotate(mDirection2);
+
+		Vector3 intersectPosition = getPositionOnPlane(camera, mCurrentPointerPos);
+		Vector3 positionDelta = intersectPosition - mStartClickPosition;
+
+		mDelta.x = positionDelta.dot(worldDir1);
+		mDelta.y = positionDelta.dot(worldDir2);
+	}
+
+	Vector3 HandleSliderPlane::getPositionOnPlane(const CameraPtr& camera, const Vector2I& pointerPos) const
+	{
+		Vector3 worldDir1 = getRotation().rotate(mDirection1);
+		Vector3 worldDir2 = getRotation().rotate(mDirection2);
+
+		Vector3 normal = worldDir1.cross(worldDir2);
+		float dot = normal.dot(camera->getForward());
+		if (dot > 0)
+			normal = -normal;
+
+		Plane plane(normal, mStartPlanePosition);
+
+		Ray clickRay = camera->screenPointToRay(pointerPos);
+		auto intersectResult = plane.intersects(clickRay);
+		if (intersectResult.first)
+			return clickRay.getPoint(intersectResult.second);
+
+		return mStartClickPosition;
+	}
 }

+ 15 - 5
BansheeEngine/Include/BsDrawHelper.h

@@ -56,6 +56,11 @@ namespace BansheeEngine
 		 */
 		void setTransform(const Matrix4& transform);
 
+		/**
+		 * Sets the layer bitfield that can be used for filtering which objects are output into the final mesh.
+		 */
+		void setLayer(UINT64 layer);
+
 		/**
 		 * @brief	Records a solid cuboid with the specified properties in the internal draw queue.
 		 */
@@ -138,17 +143,20 @@ namespace BansheeEngine
 		 *			The meshes can be accessed via getMeshes() and released via clearMeshes(). 
 		 *			Any previously active meshes will be cleared when this method is called.
 		 *
-		 * @param	sorting		Determines how (and if) should elements be sorted
+		 * @param	sorting		(optional) Determines how (and if) should elements be sorted
 		 *						based on their distance from the reference point.
-		 * @param	reference	Reference point to use for determining distance when
+		 * @param	reference	(optional) Reference point to use for determining distance when
 		 *						sorting.
+		 * @param	layers		(optional) Layers bitfield that can be used for controlling which shapes will be included
+		 *						in the mesh. This bitfield will be ANDed with the layer specified when recording the shape.
 		 *
-		 * @note	You must call releaseSolidMesh() when done.
+		 * @note	You must call clearMeshes() when done.
 		 */
-		void buildMeshes(SortType sorting = SortType::None, const Vector3& reference = Vector3::ZERO);
+		void buildMeshes(SortType sorting = SortType::None, const Vector3& reference = Vector3::ZERO, 
+			UINT64 layers = 0xFFFFFFFFFFFFFFFF);
 
 		/**
-		 * @brief	Returns a set of meshes you have previously built using buildMeshes().
+		 * @brief	Returns a set of meshes that were previously built using buildMeshes().
 		 */
 		const Vector<ShapeMeshData>& getMeshes() const { return mMeshes; }
 
@@ -163,6 +171,7 @@ namespace BansheeEngine
 			Color color;
 			Matrix4 transform;
 			Vector3 center;
+			UINT64 layer;
 		};
 
 		struct CubeData : public CommonData
@@ -238,6 +247,7 @@ namespace BansheeEngine
 
 		Color mColor;
 		Matrix4 mTransform;
+		UINT64 mLayer;
 
 		Vector<CubeData> mSolidCubeData;
 		Vector<CubeData> mWireCubeData;

+ 130 - 41
BansheeEngine/Source/BsDrawHelper.cpp

@@ -14,6 +14,7 @@ namespace BansheeEngine
 	const UINT32 DrawHelper::INDEX_BUFFER_GROWTH = 4096 * 2;
 
 	DrawHelper::DrawHelper()
+		:mLayer(1)
 	{
 		mTransform = Matrix4::IDENTITY;
 
@@ -51,6 +52,11 @@ namespace BansheeEngine
 		mTransform = transform;
 	}
 
+	void DrawHelper::setLayer(UINT64 layer)
+	{
+		mLayer = layer;
+	}
+
 	void DrawHelper::cube(const Vector3& position, const Vector3& extents)
 	{
 		mSolidCubeData.push_back(CubeData());
@@ -60,6 +66,7 @@ namespace BansheeEngine
 		cubeData.extents = extents;
 		cubeData.color = mColor;
 		cubeData.transform = mTransform;
+		cubeData.layer = mLayer;
 		cubeData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -73,6 +80,7 @@ namespace BansheeEngine
 		sphereData.quality = quality;
 		sphereData.color = mColor;
 		sphereData.transform = mTransform;
+		sphereData.layer = mLayer;
 		sphereData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -85,6 +93,7 @@ namespace BansheeEngine
 		cubeData.extents = extents;
 		cubeData.color = mColor;
 		cubeData.transform = mTransform;
+		cubeData.layer = mLayer;
 		cubeData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -98,6 +107,7 @@ namespace BansheeEngine
 		sphereData.quality = quality;
 		sphereData.color = mColor;
 		sphereData.transform = mTransform;
+		sphereData.layer = mLayer;
 		sphereData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -110,6 +120,7 @@ namespace BansheeEngine
 		lineData.end = end;
 		lineData.color = mColor;
 		lineData.transform = mTransform;
+		lineData.layer = mLayer;
 		lineData.center = mTransform.multiplyAffine((start + end) * 0.5f);
 	}
 
@@ -125,6 +136,7 @@ namespace BansheeEngine
 		frustumData.far = far;
 		frustumData.color = mColor;
 		frustumData.transform = mTransform;
+		frustumData.layer = mLayer;
 		frustumData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -140,6 +152,7 @@ namespace BansheeEngine
 		coneData.quality = quality;
 		coneData.color = mColor;
 		coneData.transform = mTransform;
+		coneData.layer = mLayer;
 		coneData.center = mTransform.multiplyAffine(base + normal * height * 0.5f);
 	}
 
@@ -154,6 +167,7 @@ namespace BansheeEngine
 		discData.quality = quality;
 		discData.color = mColor;
 		discData.transform = mTransform;
+		discData.layer = mLayer;
 		discData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -168,6 +182,7 @@ namespace BansheeEngine
 		discData.quality = quality;
 		discData.color = mColor;
 		discData.transform = mTransform;
+		discData.layer = mLayer;
 		discData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -185,6 +200,7 @@ namespace BansheeEngine
 		arcData.quality = quality;
 		arcData.color = mColor;
 		arcData.transform = mTransform;
+		arcData.layer = mLayer;
 		arcData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -202,6 +218,7 @@ namespace BansheeEngine
 		arcData.quality = quality;
 		arcData.color = mColor;
 		arcData.transform = mTransform;
+		arcData.layer = mLayer;
 		arcData.center = mTransform.multiplyAffine(position);
 	}
 
@@ -213,6 +230,7 @@ namespace BansheeEngine
 		rectData.area = area;
 		rectData.color = mColor;
 		rectData.transform = mTransform;
+		rectData.layer = mLayer;
 		rectData.center = mTransform.multiplyAffine(area.getCenter());
 	}
 
@@ -227,6 +245,7 @@ namespace BansheeEngine
 		textData.position = position;
 		textData.color = mColor;
 		textData.transform = mTransform;
+		textData.layer = mLayer;
 		textData.center = mTransform.multiplyAffine(position);
 		textData.text = text;
 		textData.font = font;
@@ -251,7 +270,7 @@ namespace BansheeEngine
 		mText2DData.clear();
 	}
 
-	void DrawHelper::buildMeshes(SortType sorting, const Vector3& reference)
+	void DrawHelper::buildMeshes(SortType sorting, const Vector3& reference, UINT64 layers)
 	{
 		clearMeshes();
 
@@ -276,17 +295,20 @@ namespace BansheeEngine
 		/* 			Sort everything according to specified sorting rule         */
 		/************************************************************************/
 
-		UINT32 totalNumShapes = (UINT32)(mSolidCubeData.size() + mSolidSphereData.size() + 
-			mWireCubeData.size() + mWireSphereData.size() + mLineData.size() + mFrustumData.size() + mConeData.size() +
-			mDiscData.size() + mWireDiscData.size() + mArcData.size() + mWireArcData.size() + mRect3Data.size() + mText2DData.size());
-
 		UINT32 idx = 0;
-		Vector<RawData> allShapes(totalNumShapes);
+		Vector<RawData> allShapes;
 
 		UINT32 localIdx = 0;
 		for (auto& shapeData : mSolidCubeData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -295,13 +317,19 @@ namespace BansheeEngine
 			rawData.distance = shapeData.center.distance(reference);
 
 			ShapeMeshes3D::getNumElementsAABox(rawData.numVertices, rawData.numIndices);
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mSolidSphereData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -311,14 +339,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsSphere(shapeData.quality, 
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mConeData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -328,14 +361,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsCone(shapeData.quality, 
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mDiscData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -345,14 +383,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsDisc(shapeData.quality,
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mArcData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -362,14 +405,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsArc(shapeData.quality, 
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mRect3Data)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -378,13 +426,19 @@ namespace BansheeEngine
 			rawData.distance = shapeData.center.distance(reference);
 
 			ShapeMeshes3D::getNumElementsQuad(rawData.numVertices, rawData.numIndices);
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mWireCubeData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -393,13 +447,19 @@ namespace BansheeEngine
 			rawData.distance = shapeData.center.distance(reference);
 
 			ShapeMeshes3D::getNumElementsWireAABox(rawData.numVertices, rawData.numIndices);
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mWireSphereData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -409,14 +469,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsWireSphere(shapeData.quality,
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mLineData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -425,13 +490,19 @@ namespace BansheeEngine
 			rawData.distance = shapeData.center.distance(reference);
 			rawData.numVertices = 2;
 			rawData.numIndices = 2;
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mFrustumData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -440,13 +511,19 @@ namespace BansheeEngine
 			rawData.distance = shapeData.center.distance(reference);
 
 			ShapeMeshes3D::getNumElementsFrustum(rawData.numVertices, rawData.numIndices);
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mWireDiscData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -456,14 +533,19 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsWireDisc(shapeData.quality, 
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		localIdx = 0;
 		for (auto& shapeData : mWireArcData)
 		{
-			RawData& rawData = allShapes[idx];
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
+			allShapes.push_back(RawData());
+			RawData& rawData = allShapes.back();
 
 			rawData.idx = localIdx++;
 			rawData.textIdx = 0;
@@ -473,8 +555,6 @@ namespace BansheeEngine
 
 			ShapeMeshes3D::getNumElementsWireArc(shapeData.quality,
 				rawData.numVertices, rawData.numIndices);
-
-			idx++;
 		}
 
 		struct TextRenderData
@@ -489,6 +569,12 @@ namespace BansheeEngine
 		localIdx = 0;
 		for (auto& shapeData : mText2DData)
 		{
+			if ((shapeData.layer & layers) == 0)
+			{
+				localIdx++;
+				continue;
+			}
+
 			SPtr<TextData<>> textData = bs_shared_ptr_new<TextData<>>(shapeData.text, shapeData.font, shapeData.size);
 
 			UINT32 numPages = textData->getNumPages();
@@ -496,7 +582,8 @@ namespace BansheeEngine
 			{
 				UINT32 numQuads = textData->getNumQuadsForPage(j);
 
-				RawData& rawData = allShapes[idx];
+				allShapes.push_back(RawData());
+				RawData& rawData = allShapes.back();
 
 				rawData.idx = localIdx;
 				rawData.textIdx = textIdx;
@@ -547,8 +634,10 @@ namespace BansheeEngine
 			UINT32 numIndices;
 		};
 
+		UINT32 numShapes = (UINT32)allShapes.size();
+
 		Vector<Batch> batches;
-		if (totalNumShapes > 0)
+		if (numShapes > 0)
 		{
 			batches.push_back(Batch());
 
@@ -566,7 +655,7 @@ namespace BansheeEngine
 				}
 			}
 
-			for (UINT32 i = 1; i < totalNumShapes; i++)
+			for (UINT32 i = 1; i < numShapes; i++)
 			{
 				Batch& currentBatch = batches.back();
 
@@ -611,7 +700,7 @@ namespace BansheeEngine
 
 			{
 				Batch& currentBatch = batches.back();
-				currentBatch.endIdx = totalNumShapes - 1;
+				currentBatch.endIdx = numShapes - 1;
 			}
 		}
 

+ 13 - 0
MBansheeEditor/Scene/HandleDrawing.cs

@@ -1,5 +1,6 @@
 using System.Runtime.CompilerServices;
 using BansheeEngine;
+using System;
 
 namespace BansheeEditor
 {
@@ -25,6 +26,15 @@ namespace BansheeEditor
             set { Internal_SetTransform(ref value); }
         }
 
+        /// <summary>
+        /// Layer bitfield that controls whether a handle is considered visible in a specific camera. Handle layer 
+        /// must match camera layer in order for the camera to render it.
+        /// </summary>
+        public static UInt64 Layer
+        {
+            set { Internal_SetLayer(value); }
+        }
+
         /// <summary>
         /// Draws an axis aligned solid cube.
         /// </summary>
@@ -176,6 +186,9 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetTransform(ref Matrix4 transform);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayer(UInt64 layer);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_DrawCube(ref Vector3 position, ref Vector3 extents, float size);
 

+ 5 - 3
MBansheeEditor/Scene/HandleSliderDisc.cs

@@ -18,10 +18,11 @@ namespace BansheeEditor
         /// <param name="radius">Radius of the disc.</param>
         /// <param name="fixedScale">If true the handle slider will always try to maintain the same visible area in the 
         ///                          viewport regardless of distance from camera.</param>
-        public HandleSliderDisc(Handle parentHandle, Vector3 normal, float radius, bool fixedScale = true)
+        /// <param name="layer">Layer that allows filtering of which sliders are interacted with from a specific camera.</param>
+        public HandleSliderDisc(Handle parentHandle, Vector3 normal, float radius, bool fixedScale = true, UInt64 layer = 1)
             :base(parentHandle)
         {
-            Internal_CreateInstance(this, ref normal, radius, fixedScale);
+            Internal_CreateInstance(this, ref normal, radius, fixedScale, layer);
         }
 
         /// <summary>
@@ -63,7 +64,8 @@ namespace BansheeEditor
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(HandleSliderDisc instance, ref Vector3 normal, float radius, bool fixedScale);
+        private static extern void Internal_CreateInstance(HandleSliderDisc instance, ref Vector3 normal, float radius, 
+            bool fixedScale, UInt64 layer);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetDelta(IntPtr nativeInstance, out float value);

+ 5 - 3
MBansheeEditor/Scene/HandleSliderLine.cs

@@ -18,10 +18,11 @@ namespace BansheeEditor
         /// <param name="length">Length of the line.</param>
         /// <param name="fixedScale">If true the handle slider will always try to maintain the same visible area in the
         ///                          viewport regardless of distance from camera.</param>
-        public HandleSliderLine(Handle parentHandle, Vector3 direction, float length, bool fixedScale = true)
+        /// <param name="layer">Layer that allows filtering of which sliders are interacted with from a specific camera.</param>
+        public HandleSliderLine(Handle parentHandle, Vector3 direction, float length, bool fixedScale = true, UInt64 layer = 1)
             :base(parentHandle)
         {
-            Internal_CreateInstance(this, ref direction, length, fixedScale);
+            Internal_CreateInstance(this, ref direction, length, fixedScale, layer);
         }
 
         /// <summary>
@@ -39,7 +40,8 @@ namespace BansheeEditor
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(HandleSliderLine instance, ref Vector3 direction, float length, bool fixedScale);
+        private static extern void Internal_CreateInstance(HandleSliderLine instance, ref Vector3 direction, float length, 
+            bool fixedScale, UInt64 layer);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetDelta(IntPtr nativeInstance, out float value);

+ 6 - 4
MBansheeEditor/Scene/HandleSliderPlane.cs

@@ -9,7 +9,7 @@ namespace BansheeEditor
     /// is internally by a quadrilateral (a bounded plane).
     /// </summary>
     public sealed class HandleSliderPlane : HandleSlider
-    {        
+    {
         /// <summary>
         /// Creates a new plane handle slider. 
         /// </summary>
@@ -21,10 +21,11 @@ namespace BansheeEditor
         /// <param name="length">Length of the quadrilateral in both directions.</param>
         /// <param name="fixedScale">If true the handle slider will always try to maintain the same visible area in the
         ///                          viewport regardless of distance from camera.</param>
-        public HandleSliderPlane(Handle parentHandle, Vector3 dir1, Vector3 dir2, float length, bool fixedScale = true)
+        /// <param name="layer">Layer that allows filtering of which sliders are interacted with from a specific camera.</param>
+        public HandleSliderPlane(Handle parentHandle, Vector3 dir1, Vector3 dir2, float length, bool fixedScale = true, UInt64 layer = 1)
             :base(parentHandle)
         {
-            Internal_CreateInstance(this, ref dir1, ref dir2, length, fixedScale);
+            Internal_CreateInstance(this, ref dir1, ref dir2, length, fixedScale, layer);
         }
 
         /// <summary>
@@ -43,7 +44,8 @@ namespace BansheeEditor
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(HandleSliderPlane instance, ref Vector3 dir1, ref Vector3 dir2, float length, bool fixedScale);
+        private static extern void Internal_CreateInstance(HandleSliderPlane instance, ref Vector3 dir1, ref Vector3 dir2, 
+            float length, bool fixedScale, UInt64 layer);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetDelta(IntPtr nativeInstance, out Vector2 value);

+ 245 - 244
MBansheeEditor/Scene/MoveHandle.cs

@@ -1,244 +1,245 @@
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Handle that allows an object to be translated along the three primary axes.
-    /// </summary>
-    public sealed class MoveHandle : DefaultHandle
-    {
-        private const float CONE_HEIGHT = 0.25f;
-        private const float CONE_RADIUS = 0.175f;
-
-        private Vector3 delta;
-
-        private HandleSliderLine xAxis;
-        private HandleSliderLine yAxis;
-        private HandleSliderLine zAxis;
-
-        private HandleSliderPlane xyPlane;
-        private HandleSliderPlane yzPlane;
-        private HandleSliderPlane zxPlane;
-
-        /// <summary>
-        /// Returns the amount of translation since last frame. Only valid while the handle is being dragged.
-        /// </summary>
-        public Vector3 Delta
-        {
-            get { return delta; }
-        }
-
-        /// <inheritdoc/>
-        internal override bool IsDragged()
-        {
-            return xAxis.State == HandleSlider.StateType.Active ||
-                    yAxis.State == HandleSlider.StateType.Active ||
-                    zAxis.State == HandleSlider.StateType.Active ||
-                    xyPlane.State == HandleSlider.StateType.Active ||
-                    yzPlane.State == HandleSlider.StateType.Active ||
-                    zxPlane.State == HandleSlider.StateType.Active;
-        }
-
-        /// <summary>
-        /// Creates a new move handle.
-        /// </summary>
-        public MoveHandle()
-        {
-            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
-            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
-            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
-
-            xyPlane = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.3f);
-            yzPlane = new HandleSliderPlane(this, Vector3.YAxis, Vector3.ZAxis, 0.3f);
-            zxPlane = new HandleSliderPlane(this, Vector3.ZAxis, Vector3.XAxis, 0.3f);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PreInput()
-        {
-            xAxis.Position = position;
-            yAxis.Position = position;
-            zAxis.Position = position;
-
-            xyPlane.Position = position;
-            yzPlane.Position = position;
-            zxPlane.Position = position;
-
-            xAxis.Rotation = rotation;
-            yAxis.Rotation = rotation;
-            zAxis.Rotation = rotation;
-
-            xyPlane.Rotation = rotation;
-            yzPlane.Rotation = rotation;
-            zxPlane.Rotation = rotation;
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PostInput()
-        {
-            delta = Vector3.Zero;
-
-            if (Handles.MoveHandleSnapActive)
-            {
-                delta += Handles.SnapValue(xAxis.Delta, Handles.MoveSnapAmount) * GetXDir();
-                delta += Handles.SnapValue(yAxis.Delta, Handles.MoveSnapAmount) * GetYDir();
-                delta += Handles.SnapValue(zAxis.Delta, Handles.MoveSnapAmount) * GetZDir();
-
-                delta += Handles.SnapValue(xyPlane.Delta.x, Handles.MoveSnapAmount) * GetXDir();
-                delta += Handles.SnapValue(xyPlane.Delta.y, Handles.MoveSnapAmount) * GetYDir();
-                delta += Handles.SnapValue(yzPlane.Delta.x, Handles.MoveSnapAmount) * GetYDir();
-                delta += Handles.SnapValue(yzPlane.Delta.y, Handles.MoveSnapAmount) * GetZDir();
-                delta += Handles.SnapValue(zxPlane.Delta.x, Handles.MoveSnapAmount) * GetZDir();
-                delta += Handles.SnapValue(zxPlane.Delta.y, Handles.MoveSnapAmount) * GetXDir();
-            }
-            else
-            {
-                delta += xAxis.Delta * GetXDir();
-                delta += yAxis.Delta * GetYDir();
-                delta += zAxis.Delta * GetZDir();
-
-                delta += xyPlane.Delta.x * GetXDir();
-                delta += xyPlane.Delta.y * GetYDir();
-                delta += yzPlane.Delta.x * GetYDir();
-                delta += yzPlane.Delta.y * GetZDir();
-                delta += zxPlane.Delta.x * GetZDir();
-                delta += zxPlane.Delta.y * GetXDir();
-            }
-        }
-
-        /// <inheritdoc/>
-        protected internal override void Draw()
-        {
-            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
-            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
-
-            // Draw 1D arrows
-            if (xAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if(xAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Red;
-
-            Vector3 xConeStart = Vector3.XAxis*(1.0f - CONE_HEIGHT);
-            HandleDrawing.DrawLine(Vector3.Zero, xConeStart, handleSize);
-            HandleDrawing.DrawCone(xConeStart, Vector3.XAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
-
-            if (yAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (yAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Green;
-
-            Vector3 yConeStart = Vector3.YAxis * (1.0f - CONE_HEIGHT);
-            HandleDrawing.DrawLine(Vector3.Zero, yConeStart, handleSize);
-            HandleDrawing.DrawCone(yConeStart, Vector3.YAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
-
-            if (zAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (zAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Blue;
-
-            Vector3 zConeStart = Vector3.ZAxis * (1.0f - CONE_HEIGHT);
-            HandleDrawing.DrawLine(Vector3.Zero, zConeStart, handleSize);
-            HandleDrawing.DrawCone(zConeStart, Vector3.ZAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
-
-            // Draw 2D planes
-            Color planeNormal = new Color(1.0f, 1.0f, 1.0f, 0.2f);
-            Color planeHover = new Color(1.0f, 1.0f, 1.0f, 0.4f);
-            Color planeActive = new Color(1.0f, 1.0f, 1.0f, 0.6f);
-
-            Vector3 planeXOffset = Vector3.XAxis * 0.3f;
-            Vector3 planeYOffset = Vector3.YAxis * 0.3f;
-            Vector3 planeZOffset = Vector3.ZAxis * 0.3f;
-
-            //// XY plane
-            HandleDrawing.Color = Color.Blue;
-
-            HandleDrawing.DrawLine(planeXOffset, planeXOffset + planeYOffset, handleSize);
-            HandleDrawing.DrawLine(planeYOffset, planeYOffset + planeXOffset, handleSize);
-
-            if (xyPlane.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.Blue * planeActive;
-            else if (xyPlane.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.Blue * planeHover;
-            else
-                HandleDrawing.Color = Color.Blue * planeNormal;
-
-            Rect3 xyPlaneArea = new Rect3(
-                (planeXOffset + planeYOffset) * 0.5f,
-                new Vector3[] { Vector3.XAxis, Vector3.YAxis}, 
-                new float[] { 0.15f, 0.15f});
-            HandleDrawing.DrawRect(xyPlaneArea, handleSize);
-
-            //// YZ plane
-            HandleDrawing.Color = Color.Red;
-
-            HandleDrawing.DrawLine(planeYOffset, planeYOffset + planeZOffset, handleSize);
-            HandleDrawing.DrawLine(planeZOffset, planeZOffset + planeYOffset, handleSize);
-
-            if (yzPlane.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.Red * planeActive;
-            else if (yzPlane.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.Red * planeHover;
-            else
-                HandleDrawing.Color = Color.Red * planeNormal;
-
-            Rect3 yzPlaneArea = new Rect3(
-                (planeYOffset + planeZOffset) * 0.5f,
-                new Vector3[] { Vector3.YAxis, Vector3.ZAxis },
-                new float[] { 0.15f, 0.15f });
-
-            HandleDrawing.DrawRect(yzPlaneArea, handleSize);
-
-            //// ZX plane
-            HandleDrawing.Color = Color.Green;
-
-            HandleDrawing.DrawLine(planeZOffset, planeZOffset + planeXOffset, handleSize);
-            HandleDrawing.DrawLine(planeXOffset, planeXOffset + planeZOffset, handleSize);
-
-            if (zxPlane.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.Green * planeActive;
-            else if (zxPlane.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.Green * planeHover;
-            else
-                HandleDrawing.Color = Color.Green * planeNormal;
-
-            Rect3 zxPlaneArea = new Rect3(
-                (planeZOffset + planeXOffset) * 0.5f,
-                new Vector3[] { Vector3.ZAxis, Vector3.XAxis },
-                new float[] { 0.15f, 0.15f });
-            HandleDrawing.DrawRect(zxPlaneArea, handleSize);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's x axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's x axis in world space</returns>
-        private Vector3 GetXDir()
-        {
-             return rotation.Rotate(Vector3.XAxis);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's y axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's y axis in world space</returns>
-        private Vector3 GetYDir()
-        {
-            return rotation.Rotate(Vector3.YAxis);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's z axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's z axis in world space</returns>
-        private Vector3 GetZDir()
-        {
-            return rotation.Rotate(Vector3.ZAxis);
-        }
-    }
-}
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Handle that allows an object to be translated along the three primary axes.
+    /// </summary>
+    public sealed class MoveHandle : DefaultHandle
+    {
+        private const float CONE_HEIGHT = 0.25f;
+        private const float CONE_RADIUS = 0.175f;
+
+        private Vector3 delta;
+
+        private HandleSliderLine xAxis;
+        private HandleSliderLine yAxis;
+        private HandleSliderLine zAxis;
+
+        private HandleSliderPlane xyPlane;
+        private HandleSliderPlane yzPlane;
+        private HandleSliderPlane zxPlane;
+
+        /// <summary>
+        /// Returns the amount of translation since last frame. Only valid while the handle is being dragged.
+        /// </summary>
+        public Vector3 Delta
+        {
+            get { return delta; }
+        }
+
+        /// <inheritdoc/>
+        internal override bool IsDragged()
+        {
+            return xAxis.State == HandleSlider.StateType.Active ||
+                    yAxis.State == HandleSlider.StateType.Active ||
+                    zAxis.State == HandleSlider.StateType.Active ||
+                    xyPlane.State == HandleSlider.StateType.Active ||
+                    yzPlane.State == HandleSlider.StateType.Active ||
+                    zxPlane.State == HandleSlider.StateType.Active;
+        }
+
+        /// <summary>
+        /// Creates a new move handle.
+        /// </summary>
+        public MoveHandle()
+        {
+            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
+            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
+            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
+
+            xyPlane = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.3f);
+            yzPlane = new HandleSliderPlane(this, Vector3.YAxis, Vector3.ZAxis, 0.3f);
+            zxPlane = new HandleSliderPlane(this, Vector3.ZAxis, Vector3.XAxis, 0.3f);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PreInput()
+        {
+            xAxis.Position = position;
+            yAxis.Position = position;
+            zAxis.Position = position;
+
+            xyPlane.Position = position;
+            yzPlane.Position = position;
+            zxPlane.Position = position;
+
+            xAxis.Rotation = rotation;
+            yAxis.Rotation = rotation;
+            zAxis.Rotation = rotation;
+
+            xyPlane.Rotation = rotation;
+            yzPlane.Rotation = rotation;
+            zxPlane.Rotation = rotation;
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PostInput()
+        {
+            delta = Vector3.Zero;
+
+            if (Handles.MoveHandleSnapActive)
+            {
+                delta += Handles.SnapValue(xAxis.Delta, Handles.MoveSnapAmount) * GetXDir();
+                delta += Handles.SnapValue(yAxis.Delta, Handles.MoveSnapAmount) * GetYDir();
+                delta += Handles.SnapValue(zAxis.Delta, Handles.MoveSnapAmount) * GetZDir();
+
+                delta += Handles.SnapValue(xyPlane.Delta.x, Handles.MoveSnapAmount) * GetXDir();
+                delta += Handles.SnapValue(xyPlane.Delta.y, Handles.MoveSnapAmount) * GetYDir();
+                delta += Handles.SnapValue(yzPlane.Delta.x, Handles.MoveSnapAmount) * GetYDir();
+                delta += Handles.SnapValue(yzPlane.Delta.y, Handles.MoveSnapAmount) * GetZDir();
+                delta += Handles.SnapValue(zxPlane.Delta.x, Handles.MoveSnapAmount) * GetZDir();
+                delta += Handles.SnapValue(zxPlane.Delta.y, Handles.MoveSnapAmount) * GetXDir();
+            }
+            else
+            {
+                delta += xAxis.Delta * GetXDir();
+                delta += yAxis.Delta * GetYDir();
+                delta += zAxis.Delta * GetZDir();
+
+                delta += xyPlane.Delta.x * GetXDir();
+                delta += xyPlane.Delta.y * GetYDir();
+                delta += yzPlane.Delta.x * GetYDir();
+                delta += yzPlane.Delta.y * GetZDir();
+                delta += zxPlane.Delta.x * GetZDir();
+                delta += zxPlane.Delta.y * GetXDir();
+            }
+        }
+
+        /// <inheritdoc/>
+        protected internal override void Draw()
+        {
+            HandleDrawing.Layer = 1;
+            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
+            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
+
+            // Draw 1D arrows
+            if (xAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if(xAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Red;
+
+            Vector3 xConeStart = Vector3.XAxis*(1.0f - CONE_HEIGHT);
+            HandleDrawing.DrawLine(Vector3.Zero, xConeStart, handleSize);
+            HandleDrawing.DrawCone(xConeStart, Vector3.XAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
+
+            if (yAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (yAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Green;
+
+            Vector3 yConeStart = Vector3.YAxis * (1.0f - CONE_HEIGHT);
+            HandleDrawing.DrawLine(Vector3.Zero, yConeStart, handleSize);
+            HandleDrawing.DrawCone(yConeStart, Vector3.YAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
+
+            if (zAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (zAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Blue;
+
+            Vector3 zConeStart = Vector3.ZAxis * (1.0f - CONE_HEIGHT);
+            HandleDrawing.DrawLine(Vector3.Zero, zConeStart, handleSize);
+            HandleDrawing.DrawCone(zConeStart, Vector3.ZAxis, CONE_HEIGHT, CONE_RADIUS, handleSize);
+
+            // Draw 2D planes
+            Color planeNormal = new Color(1.0f, 1.0f, 1.0f, 0.2f);
+            Color planeHover = new Color(1.0f, 1.0f, 1.0f, 0.4f);
+            Color planeActive = new Color(1.0f, 1.0f, 1.0f, 0.6f);
+
+            Vector3 planeXOffset = Vector3.XAxis * 0.3f;
+            Vector3 planeYOffset = Vector3.YAxis * 0.3f;
+            Vector3 planeZOffset = Vector3.ZAxis * 0.3f;
+
+            //// XY plane
+            HandleDrawing.Color = Color.Blue;
+
+            HandleDrawing.DrawLine(planeXOffset, planeXOffset + planeYOffset, handleSize);
+            HandleDrawing.DrawLine(planeYOffset, planeYOffset + planeXOffset, handleSize);
+
+            if (xyPlane.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.Blue * planeActive;
+            else if (xyPlane.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.Blue * planeHover;
+            else
+                HandleDrawing.Color = Color.Blue * planeNormal;
+
+            Rect3 xyPlaneArea = new Rect3(
+                (planeXOffset + planeYOffset) * 0.5f,
+                new Vector3[] { Vector3.XAxis, Vector3.YAxis}, 
+                new float[] { 0.15f, 0.15f});
+            HandleDrawing.DrawRect(xyPlaneArea, handleSize);
+
+            //// YZ plane
+            HandleDrawing.Color = Color.Red;
+
+            HandleDrawing.DrawLine(planeYOffset, planeYOffset + planeZOffset, handleSize);
+            HandleDrawing.DrawLine(planeZOffset, planeZOffset + planeYOffset, handleSize);
+
+            if (yzPlane.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.Red * planeActive;
+            else if (yzPlane.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.Red * planeHover;
+            else
+                HandleDrawing.Color = Color.Red * planeNormal;
+
+            Rect3 yzPlaneArea = new Rect3(
+                (planeYOffset + planeZOffset) * 0.5f,
+                new Vector3[] { Vector3.YAxis, Vector3.ZAxis },
+                new float[] { 0.15f, 0.15f });
+
+            HandleDrawing.DrawRect(yzPlaneArea, handleSize);
+
+            //// ZX plane
+            HandleDrawing.Color = Color.Green;
+
+            HandleDrawing.DrawLine(planeZOffset, planeZOffset + planeXOffset, handleSize);
+            HandleDrawing.DrawLine(planeXOffset, planeXOffset + planeZOffset, handleSize);
+
+            if (zxPlane.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.Green * planeActive;
+            else if (zxPlane.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.Green * planeHover;
+            else
+                HandleDrawing.Color = Color.Green * planeNormal;
+
+            Rect3 zxPlaneArea = new Rect3(
+                (planeZOffset + planeXOffset) * 0.5f,
+                new Vector3[] { Vector3.ZAxis, Vector3.XAxis },
+                new float[] { 0.15f, 0.15f });
+            HandleDrawing.DrawRect(zxPlaneArea, handleSize);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's x axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's x axis in world space</returns>
+        private Vector3 GetXDir()
+        {
+             return rotation.Rotate(Vector3.XAxis);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's y axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's y axis in world space</returns>
+        private Vector3 GetYDir()
+        {
+            return rotation.Rotate(Vector3.YAxis);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's z axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's z axis in world space</returns>
+        private Vector3 GetZDir()
+        {
+            return rotation.Rotate(Vector3.ZAxis);
+        }
+    }
+}

+ 245 - 244
MBansheeEditor/Scene/RotateHandle.cs

@@ -1,244 +1,245 @@
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Handle that allows an object to be rotated around the three primary axes, as well as a free axis currently
-    /// facing the camera.
-    /// </summary>
-    public sealed class RotateHandle : DefaultHandle
-    {
-        private Quaternion delta;
-
-        private HandleSliderDisc xAxis;
-        private HandleSliderDisc yAxis;
-        private HandleSliderDisc zAxis;
-
-        private HandleSliderDisc freeAxis;
-
-        private bool isDragged;
-        private Quaternion dragStartRotation;
-
-        /// <summary>
-        /// Amount of rotation applied since the last frame. Only valid while the handle is being dragged.
-        /// </summary>
-        public Quaternion Delta
-        {
-            get { return delta; }
-        }
-
-        /// <inheritdoc/>
-        internal override bool IsDragged()
-        {
-            return xAxis.State == HandleSlider.StateType.Active ||
-                    yAxis.State == HandleSlider.StateType.Active ||
-                    zAxis.State == HandleSlider.StateType.Active ||
-                    freeAxis.State == HandleSlider.StateType.Active;
-        }
-
-        /// <summary>
-        /// Creates a new rotation handle.
-        /// </summary>
-        public RotateHandle()
-        {
-            xAxis = new HandleSliderDisc(this, Vector3.XAxis, 1.0f);
-            yAxis = new HandleSliderDisc(this, Vector3.YAxis, 1.0f);
-            zAxis = new HandleSliderDisc(this, Vector3.ZAxis, 1.0f);
-            freeAxis = new HandleSliderDisc(this, -Vector3.ZAxis, 1.2f);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PreInput()
-        {
-            xAxis.Position = position;
-            yAxis.Position = position;
-            zAxis.Position = position;
-            freeAxis.Position = position;
-
-            Quaternion handleRotation = isDragged ? dragStartRotation : Rotation;
-            xAxis.Rotation = handleRotation;
-            yAxis.Rotation = handleRotation;
-            zAxis.Rotation = handleRotation;
-            freeAxis.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
-
-            xAxis.SetCutoffPlane(GetXStartAngle(isDragged), true);
-            yAxis.SetCutoffPlane(GetYStartAngle(isDragged), true);
-            zAxis.SetCutoffPlane(GetZStartAngle(isDragged), true);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PostInput()
-        {
-            if (IsDragged())
-            {
-                if (!isDragged)
-                {
-                    isDragged = true;
-                    dragStartRotation = Rotation;
-                }
-            }
-            else
-            {
-                isDragged = false;
-                dragStartRotation = Quaternion.Identity;
-            }
-
-            Degree xValue = 0.0f;
-            Degree yValue = 0.0f;
-            Degree zValue = 0.0f;
-            Degree freeAxisValue = 0.0f;
-
-            if (Handles.RotateHandleSnapActive)
-            {
-                xValue = Handles.SnapValue(xAxis.Delta, Handles.RotateSnapAmount);
-                yValue = Handles.SnapValue(yAxis.Delta, Handles.RotateSnapAmount);
-                zValue = Handles.SnapValue(zAxis.Delta, Handles.RotateSnapAmount);
-                freeAxisValue = Handles.SnapValue(freeAxis.Delta, Handles.RotateSnapAmount);
-            }
-            else
-            {
-                xValue = xAxis.Delta;
-                yValue = yAxis.Delta;
-                zValue = zAxis.Delta;
-                freeAxisValue = freeAxis.Delta;
-            }
-
-            Vector3 cameraForward = -(dragStartRotation.Inverse * EditorApplication.SceneViewCamera.SceneObject.Rotation).Forward;
-
-            delta = Quaternion.FromEuler(xValue, yValue, zValue);
-            delta *= Quaternion.FromAxisAngle(cameraForward, freeAxisValue);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void Draw()
-        {
-            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
-            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
-
-            // Draw arcs
-            if (xAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if(xAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Red;
-
-            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.XAxis, 1.0f, GetXStartAngle(false), -180.0f, handleSize);
-
-            if (yAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (yAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Green;
-
-            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.YAxis, 1.0f, GetYStartAngle(false), -180.0f, handleSize);
-
-            if (zAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (zAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Blue;
-
-            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.ZAxis, 1.0f, GetZStartAngle(false), -180.0f, handleSize);
-
-            // Draw "bounds" and free handle
-            Color gray = new Color(1.0f, 1.0f, 1.0f, 0.3f);
-            Vector3 cameraNormal = EditorApplication.SceneViewCamera.SceneObject.Rotation.Rotate(Vector3.ZAxis);
-            HandleDrawing.Transform = Matrix4.TRS(Position, Quaternion.Identity, Vector3.One);
-            HandleDrawing.Color = gray;
-
-            HandleDrawing.DrawWireDisc(cameraNormal * 0.1f, cameraNormal, 1.0f, handleSize);
-
-            if (freeAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (freeAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = gray;
-
-            HandleDrawing.DrawWireDisc(Vector3.Zero, cameraNormal, 1.2f, handleSize);
-
-            // Draw active rotation pie
-            HandleDrawing.Color = gray;
-            HandleDrawing.Transform = Matrix4.TRS(Position, EditorApplication.SceneViewCamera.SceneObject.Rotation, Vector3.One);
-
-            if (freeAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.DrawArc(Vector3.Zero, -Vector3.ZAxis, 1.2f, freeAxis.StartAngle, freeAxis.Delta, handleSize);
-
-            HandleDrawing.Transform = Matrix4.TRS(Position, dragStartRotation, Vector3.One);
-
-            if (xAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.DrawArc(Vector3.Zero, Vector3.XAxis, 1.0f, xAxis.StartAngle, xAxis.Delta, handleSize);
-            else if (yAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.DrawArc(Vector3.Zero, Vector3.YAxis, 1.0f, yAxis.StartAngle, yAxis.Delta, handleSize);
-            else if (zAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.DrawArc(Vector3.Zero, Vector3.ZAxis, 1.0f, zAxis.StartAngle, zAxis.Delta, handleSize);
-        }
-
-        /// <summary>
-        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
-        /// the arc starts for the X axis.
-        /// </summary>
-        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
-        ///                      to the value when handle drag started. This is useful because we do not want the visible
-        ///                      arc to change while the user is in the process of rotating the handle.</param>
-        /// <returns>Angle at which to display the visible arc for the X axis rotations.</returns>
-        private Degree GetXStartAngle(bool frozen)
-        {
-            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
-
-            Vector3 xStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.XAxis);
-            return PointOnCircleToAngle(Vector3.XAxis, xStartDir);
-        }
-
-        /// <summary>
-        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
-        /// the arc starts for the Y axis.
-        /// </summary>
-        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
-        ///                      to the value when handle drag started. This is useful because we do not want the visible
-        ///                      arc to change while the user is in the process of rotating the handle.</param>
-        /// <returns>Angle at which to display the visible arc for the Y axis rotations.</returns>
-        private Degree GetYStartAngle(bool frozen)
-        {
-            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
-
-            Vector3 yStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.YAxis);
-            return PointOnCircleToAngle(Vector3.YAxis, yStartDir);
-        }
-
-        /// <summary>
-        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
-        /// the arc starts for the Z axis.
-        /// </summary>
-        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
-        ///                      to the value when handle drag started. This is useful because we do not want the visible
-        ///                      arc to change while the user is in the process of rotating the handle.</param>
-        /// <returns>Angle at which to display the visible arc for the Z axis rotations.</returns>
-        private Degree GetZStartAngle(bool frozen)
-        {
-            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
-
-            Vector3 zStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.ZAxis);
-            return PointOnCircleToAngle(Vector3.ZAxis, zStartDir);
-        }
-
-        /// <summary>
-        /// Converts a point on the circle to an angle on the circle.
-        /// </summary>
-        /// <param name="up">Up vector determining the orientation of the circle.</param>
-        /// <param name="point">Point along a unit circle centered around the origin.</param>
-        /// <returns>Angle at which the provided point is located on the circle.</returns>
-        private Degree PointOnCircleToAngle(Vector3 up, Vector3 point)
-        {
-            Quaternion rot = Quaternion.FromToRotation(up, Vector3.YAxis);
-
-            Matrix4 worldToPlane = Matrix4.TRS(Vector3.Zero, rot, Vector3.One);
-            point = worldToPlane.MultiplyDirection(point);
-
-            return (MathEx.Atan2(-point.z, -point.x) + MathEx.Pi) * MathEx.Rad2Deg;
-        }
-    }
-}
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Handle that allows an object to be rotated around the three primary axes, as well as a free axis currently
+    /// facing the camera.
+    /// </summary>
+    public sealed class RotateHandle : DefaultHandle
+    {
+        private Quaternion delta;
+
+        private HandleSliderDisc xAxis;
+        private HandleSliderDisc yAxis;
+        private HandleSliderDisc zAxis;
+
+        private HandleSliderDisc freeAxis;
+
+        private bool isDragged;
+        private Quaternion dragStartRotation;
+
+        /// <summary>
+        /// Amount of rotation applied since the last frame. Only valid while the handle is being dragged.
+        /// </summary>
+        public Quaternion Delta
+        {
+            get { return delta; }
+        }
+
+        /// <inheritdoc/>
+        internal override bool IsDragged()
+        {
+            return xAxis.State == HandleSlider.StateType.Active ||
+                    yAxis.State == HandleSlider.StateType.Active ||
+                    zAxis.State == HandleSlider.StateType.Active ||
+                    freeAxis.State == HandleSlider.StateType.Active;
+        }
+
+        /// <summary>
+        /// Creates a new rotation handle.
+        /// </summary>
+        public RotateHandle()
+        {
+            xAxis = new HandleSliderDisc(this, Vector3.XAxis, 1.0f);
+            yAxis = new HandleSliderDisc(this, Vector3.YAxis, 1.0f);
+            zAxis = new HandleSliderDisc(this, Vector3.ZAxis, 1.0f);
+            freeAxis = new HandleSliderDisc(this, -Vector3.ZAxis, 1.2f);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PreInput()
+        {
+            xAxis.Position = position;
+            yAxis.Position = position;
+            zAxis.Position = position;
+            freeAxis.Position = position;
+
+            Quaternion handleRotation = isDragged ? dragStartRotation : Rotation;
+            xAxis.Rotation = handleRotation;
+            yAxis.Rotation = handleRotation;
+            zAxis.Rotation = handleRotation;
+            freeAxis.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
+
+            xAxis.SetCutoffPlane(GetXStartAngle(isDragged), true);
+            yAxis.SetCutoffPlane(GetYStartAngle(isDragged), true);
+            zAxis.SetCutoffPlane(GetZStartAngle(isDragged), true);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PostInput()
+        {
+            if (IsDragged())
+            {
+                if (!isDragged)
+                {
+                    isDragged = true;
+                    dragStartRotation = Rotation;
+                }
+            }
+            else
+            {
+                isDragged = false;
+                dragStartRotation = Quaternion.Identity;
+            }
+
+            Degree xValue = 0.0f;
+            Degree yValue = 0.0f;
+            Degree zValue = 0.0f;
+            Degree freeAxisValue = 0.0f;
+
+            if (Handles.RotateHandleSnapActive)
+            {
+                xValue = Handles.SnapValue(xAxis.Delta, Handles.RotateSnapAmount);
+                yValue = Handles.SnapValue(yAxis.Delta, Handles.RotateSnapAmount);
+                zValue = Handles.SnapValue(zAxis.Delta, Handles.RotateSnapAmount);
+                freeAxisValue = Handles.SnapValue(freeAxis.Delta, Handles.RotateSnapAmount);
+            }
+            else
+            {
+                xValue = xAxis.Delta;
+                yValue = yAxis.Delta;
+                zValue = zAxis.Delta;
+                freeAxisValue = freeAxis.Delta;
+            }
+
+            Vector3 cameraForward = -(dragStartRotation.Inverse * EditorApplication.SceneViewCamera.SceneObject.Rotation).Forward;
+
+            delta = Quaternion.FromEuler(xValue, yValue, zValue);
+            delta *= Quaternion.FromAxisAngle(cameraForward, freeAxisValue);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void Draw()
+        {
+            HandleDrawing.Layer = 1;
+            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
+            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
+
+            // Draw arcs
+            if (xAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if(xAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Red;
+
+            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.XAxis, 1.0f, GetXStartAngle(false), -180.0f, handleSize);
+
+            if (yAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (yAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Green;
+
+            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.YAxis, 1.0f, GetYStartAngle(false), -180.0f, handleSize);
+
+            if (zAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (zAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Blue;
+
+            HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.ZAxis, 1.0f, GetZStartAngle(false), -180.0f, handleSize);
+
+            // Draw "bounds" and free handle
+            Color gray = new Color(1.0f, 1.0f, 1.0f, 0.3f);
+            Vector3 cameraNormal = EditorApplication.SceneViewCamera.SceneObject.Rotation.Rotate(Vector3.ZAxis);
+            HandleDrawing.Transform = Matrix4.TRS(Position, Quaternion.Identity, Vector3.One);
+            HandleDrawing.Color = gray;
+
+            HandleDrawing.DrawWireDisc(cameraNormal * 0.1f, cameraNormal, 1.0f, handleSize);
+
+            if (freeAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (freeAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = gray;
+
+            HandleDrawing.DrawWireDisc(Vector3.Zero, cameraNormal, 1.2f, handleSize);
+
+            // Draw active rotation pie
+            HandleDrawing.Color = gray;
+            HandleDrawing.Transform = Matrix4.TRS(Position, EditorApplication.SceneViewCamera.SceneObject.Rotation, Vector3.One);
+
+            if (freeAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.DrawArc(Vector3.Zero, -Vector3.ZAxis, 1.2f, freeAxis.StartAngle, freeAxis.Delta, handleSize);
+
+            HandleDrawing.Transform = Matrix4.TRS(Position, dragStartRotation, Vector3.One);
+
+            if (xAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.DrawArc(Vector3.Zero, Vector3.XAxis, 1.0f, xAxis.StartAngle, xAxis.Delta, handleSize);
+            else if (yAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.DrawArc(Vector3.Zero, Vector3.YAxis, 1.0f, yAxis.StartAngle, yAxis.Delta, handleSize);
+            else if (zAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.DrawArc(Vector3.Zero, Vector3.ZAxis, 1.0f, zAxis.StartAngle, zAxis.Delta, handleSize);
+        }
+
+        /// <summary>
+        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
+        /// the arc starts for the X axis.
+        /// </summary>
+        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
+        ///                      to the value when handle drag started. This is useful because we do not want the visible
+        ///                      arc to change while the user is in the process of rotating the handle.</param>
+        /// <returns>Angle at which to display the visible arc for the X axis rotations.</returns>
+        private Degree GetXStartAngle(bool frozen)
+        {
+            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
+
+            Vector3 xStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.XAxis);
+            return PointOnCircleToAngle(Vector3.XAxis, xStartDir);
+        }
+
+        /// <summary>
+        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
+        /// the arc starts for the Y axis.
+        /// </summary>
+        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
+        ///                      to the value when handle drag started. This is useful because we do not want the visible
+        ///                      arc to change while the user is in the process of rotating the handle.</param>
+        /// <returns>Angle at which to display the visible arc for the Y axis rotations.</returns>
+        private Degree GetYStartAngle(bool frozen)
+        {
+            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
+
+            Vector3 yStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.YAxis);
+            return PointOnCircleToAngle(Vector3.YAxis, yStartDir);
+        }
+
+        /// <summary>
+        /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which 
+        /// the arc starts for the Z axis.
+        /// </summary>
+        /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
+        ///                      to the value when handle drag started. This is useful because we do not want the visible
+        ///                      arc to change while the user is in the process of rotating the handle.</param>
+        /// <returns>Angle at which to display the visible arc for the Z axis rotations.</returns>
+        private Degree GetZStartAngle(bool frozen)
+        {
+            Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
+
+            Vector3 zStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.ZAxis);
+            return PointOnCircleToAngle(Vector3.ZAxis, zStartDir);
+        }
+
+        /// <summary>
+        /// Converts a point on the circle to an angle on the circle.
+        /// </summary>
+        /// <param name="up">Up vector determining the orientation of the circle.</param>
+        /// <param name="point">Point along a unit circle centered around the origin.</param>
+        /// <returns>Angle at which the provided point is located on the circle.</returns>
+        private Degree PointOnCircleToAngle(Vector3 up, Vector3 point)
+        {
+            Quaternion rot = Quaternion.FromToRotation(up, Vector3.YAxis);
+
+            Matrix4 worldToPlane = Matrix4.TRS(Vector3.Zero, rot, Vector3.One);
+            point = worldToPlane.MultiplyDirection(point);
+
+            return (MathEx.Atan2(-point.z, -point.x) + MathEx.Pi) * MathEx.Rad2Deg;
+        }
+    }
+}

+ 183 - 182
MBansheeEditor/Scene/ScaleHandle.cs

@@ -1,182 +1,183 @@
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Handle that allows an object to be scaled along the three primary axes, as well as a free axis currently
-    /// facing the camera.
-    /// </summary>
-    public sealed class ScaleHandle : DefaultHandle
-    {
-        private const float SMALL_CUBE_SIZE = 0.175f;
-        private const float CENTER_CUBE_SIZE = 0.33f;
-
-        private Vector3 delta;
-
-        private HandleSliderLine xAxis;
-        private HandleSliderLine yAxis;
-        private HandleSliderLine zAxis;
-
-        private HandleSliderPlane freeAxis;
-
-        /// <summary>
-        /// Returns the amount of scaling applied since the last frame. Only valid while the handle is being dragged.
-        /// </summary>
-        public Vector3 Delta
-        {
-            get { return delta; }
-        }
-
-        /// <inheritdoc/>
-        internal override bool IsDragged()
-        {
-            return xAxis.State == HandleSlider.StateType.Active ||
-                    yAxis.State == HandleSlider.StateType.Active ||
-                    zAxis.State == HandleSlider.StateType.Active ||
-                    freeAxis.State == HandleSlider.StateType.Active;
-        }
-
-        /// <summary>
-        /// Creates a new scale handle.
-        /// </summary>
-        public ScaleHandle()
-        {
-            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
-            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
-            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
-
-            freeAxis = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.4f);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PreInput()
-        {
-            xAxis.Position = position;
-            yAxis.Position = position;
-            zAxis.Position = position;
-
-            xAxis.Rotation = rotation;
-            yAxis.Rotation = rotation;
-            zAxis.Rotation = rotation;
-
-            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
-            Vector3 freeAxisOffset = (Vector3.XAxis * -0.2f + Vector3.YAxis * -0.2f) * handleSize;
-            freeAxis.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
-            freeAxis.Position = position + freeAxis.Rotation.Rotate(freeAxisOffset);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void PostInput()
-        {
-            delta = Vector3.Zero;
-
-            delta += xAxis.Delta * GetXDir() * 0.1f;
-            delta += yAxis.Delta * GetYDir() * 0.1f;
-            delta += zAxis.Delta * GetZDir() * 0.1f;
-            delta += (freeAxis.Delta.x + freeAxis.Delta.y) * Vector3.One * 0.1f;
-        }
-
-        /// <inheritdoc/>
-        protected internal override void Draw()
-        {
-            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
-            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
-
-            // Draw 1D sliders
-            Vector3 smallCubeExtents = new Vector3(SMALL_CUBE_SIZE*0.5f, SMALL_CUBE_SIZE*0.5f, SMALL_CUBE_SIZE*0.5f);
-
-            if (xAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (xAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Red;
-
-            Vector3 xCubeOffset = Vector3.XAxis * SMALL_CUBE_SIZE * 0.5f;
-            Vector3 xCubeStart = Vector3.XAxis - xCubeOffset;
-            
-            HandleDrawing.DrawLine(Vector3.Zero, xCubeStart, handleSize);
-            HandleDrawing.DrawCube(xCubeStart + xCubeOffset, smallCubeExtents, handleSize);
-
-            if (yAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (yAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Green;
-
-            Vector3 yCubeOffset = Vector3.YAxis * SMALL_CUBE_SIZE * 0.5f;
-            Vector3 yCubeStart = Vector3.YAxis - yCubeOffset;
-
-            HandleDrawing.DrawLine(Vector3.Zero, yCubeStart, handleSize);
-            HandleDrawing.DrawCube(yCubeStart + yCubeOffset, smallCubeExtents, handleSize);
-
-            if (zAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (zAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.Blue;
-
-            Vector3 zCubeOffset = Vector3.ZAxis * SMALL_CUBE_SIZE * 0.5f;
-            Vector3 zCubeStart = Vector3.ZAxis - zCubeOffset;
-
-            HandleDrawing.DrawLine(Vector3.Zero, zCubeStart, handleSize);
-            HandleDrawing.DrawCube(zCubeStart + zCubeOffset, smallCubeExtents, handleSize);
-
-            // Draw free scale handle
-            if (freeAxis.State == HandleSlider.StateType.Active)
-                HandleDrawing.Color = Color.White;
-            else if (freeAxis.State == HandleSlider.StateType.Hover)
-                HandleDrawing.Color = Color.BansheeOrange;
-            else
-                HandleDrawing.Color = Color.White;
-
-            //// Rotate it so it always faces the camera, and move it forward a bit to always render in front
-            Vector3 bottomLeft = -Vector3.XAxis * 0.2f - Vector3.YAxis * 0.2f;
-            Vector3 topLeft = -Vector3.XAxis * 0.2f + Vector3.YAxis * 0.2f;
-            Vector3 topRight = Vector3.XAxis * 0.2f + Vector3.YAxis * 0.2f;
-            Vector3 bottomRight = Vector3.XAxis * 0.2f - Vector3.YAxis * 0.2f;
-
-            Vector3 offset = Vector3.ZAxis*0.1f;
-
-            Quaternion cameraRot = EditorApplication.SceneViewCamera.SceneObject.Rotation;
-            bottomLeft = cameraRot.Rotate(bottomLeft + offset);
-            topLeft = cameraRot.Rotate(topLeft + offset);
-            topRight = cameraRot.Rotate(topRight + offset);
-            bottomRight = cameraRot.Rotate(bottomRight + offset);
-
-            HandleDrawing.DrawLine(bottomLeft, bottomRight, handleSize);
-            HandleDrawing.DrawLine(bottomLeft, topLeft, handleSize);
-            HandleDrawing.DrawLine(topLeft, topRight, handleSize);
-            HandleDrawing.DrawLine(bottomRight, topRight, handleSize);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's x axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's x axis in world space</returns>
-        private Vector3 GetXDir()
-        {
-            return rotation.Rotate(Vector3.XAxis);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's y axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's y axis in world space</returns>
-        private Vector3 GetYDir()
-        {
-            return rotation.Rotate(Vector3.YAxis);
-        }
-
-        /// <summary>
-        /// Returns the direction of the handle's z axis in world space.
-        /// </summary>
-        /// <returns>Direction of the handle's z axis in world space</returns>
-        private Vector3 GetZDir()
-        {
-            return rotation.Rotate(Vector3.ZAxis);
-        }
-    }
-}
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Handle that allows an object to be scaled along the three primary axes, as well as a free axis currently
+    /// facing the camera.
+    /// </summary>
+    public sealed class ScaleHandle : DefaultHandle
+    {
+        private const float SMALL_CUBE_SIZE = 0.175f;
+        private const float CENTER_CUBE_SIZE = 0.33f;
+
+        private Vector3 delta;
+
+        private HandleSliderLine xAxis;
+        private HandleSliderLine yAxis;
+        private HandleSliderLine zAxis;
+
+        private HandleSliderPlane freeAxis;
+
+        /// <summary>
+        /// Returns the amount of scaling applied since the last frame. Only valid while the handle is being dragged.
+        /// </summary>
+        public Vector3 Delta
+        {
+            get { return delta; }
+        }
+
+        /// <inheritdoc/>
+        internal override bool IsDragged()
+        {
+            return xAxis.State == HandleSlider.StateType.Active ||
+                    yAxis.State == HandleSlider.StateType.Active ||
+                    zAxis.State == HandleSlider.StateType.Active ||
+                    freeAxis.State == HandleSlider.StateType.Active;
+        }
+
+        /// <summary>
+        /// Creates a new scale handle.
+        /// </summary>
+        public ScaleHandle()
+        {
+            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
+            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
+            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
+
+            freeAxis = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.4f);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PreInput()
+        {
+            xAxis.Position = position;
+            yAxis.Position = position;
+            zAxis.Position = position;
+
+            xAxis.Rotation = rotation;
+            yAxis.Rotation = rotation;
+            zAxis.Rotation = rotation;
+
+            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
+            Vector3 freeAxisOffset = (Vector3.XAxis * -0.2f + Vector3.YAxis * -0.2f) * handleSize;
+            freeAxis.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
+            freeAxis.Position = position + freeAxis.Rotation.Rotate(freeAxisOffset);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void PostInput()
+        {
+            delta = Vector3.Zero;
+
+            delta += xAxis.Delta * GetXDir() * 0.1f;
+            delta += yAxis.Delta * GetYDir() * 0.1f;
+            delta += zAxis.Delta * GetZDir() * 0.1f;
+            delta += (freeAxis.Delta.x + freeAxis.Delta.y) * Vector3.One * 0.1f;
+        }
+
+        /// <inheritdoc/>
+        protected internal override void Draw()
+        {
+            HandleDrawing.Layer = 1;
+            HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
+            float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
+
+            // Draw 1D sliders
+            Vector3 smallCubeExtents = new Vector3(SMALL_CUBE_SIZE*0.5f, SMALL_CUBE_SIZE*0.5f, SMALL_CUBE_SIZE*0.5f);
+
+            if (xAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (xAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Red;
+
+            Vector3 xCubeOffset = Vector3.XAxis * SMALL_CUBE_SIZE * 0.5f;
+            Vector3 xCubeStart = Vector3.XAxis - xCubeOffset;
+            
+            HandleDrawing.DrawLine(Vector3.Zero, xCubeStart, handleSize);
+            HandleDrawing.DrawCube(xCubeStart + xCubeOffset, smallCubeExtents, handleSize);
+
+            if (yAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (yAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Green;
+
+            Vector3 yCubeOffset = Vector3.YAxis * SMALL_CUBE_SIZE * 0.5f;
+            Vector3 yCubeStart = Vector3.YAxis - yCubeOffset;
+
+            HandleDrawing.DrawLine(Vector3.Zero, yCubeStart, handleSize);
+            HandleDrawing.DrawCube(yCubeStart + yCubeOffset, smallCubeExtents, handleSize);
+
+            if (zAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (zAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.Blue;
+
+            Vector3 zCubeOffset = Vector3.ZAxis * SMALL_CUBE_SIZE * 0.5f;
+            Vector3 zCubeStart = Vector3.ZAxis - zCubeOffset;
+
+            HandleDrawing.DrawLine(Vector3.Zero, zCubeStart, handleSize);
+            HandleDrawing.DrawCube(zCubeStart + zCubeOffset, smallCubeExtents, handleSize);
+
+            // Draw free scale handle
+            if (freeAxis.State == HandleSlider.StateType.Active)
+                HandleDrawing.Color = Color.White;
+            else if (freeAxis.State == HandleSlider.StateType.Hover)
+                HandleDrawing.Color = Color.BansheeOrange;
+            else
+                HandleDrawing.Color = Color.White;
+
+            //// Rotate it so it always faces the camera, and move it forward a bit to always render in front
+            Vector3 bottomLeft = -Vector3.XAxis * 0.2f - Vector3.YAxis * 0.2f;
+            Vector3 topLeft = -Vector3.XAxis * 0.2f + Vector3.YAxis * 0.2f;
+            Vector3 topRight = Vector3.XAxis * 0.2f + Vector3.YAxis * 0.2f;
+            Vector3 bottomRight = Vector3.XAxis * 0.2f - Vector3.YAxis * 0.2f;
+
+            Vector3 offset = Vector3.ZAxis*0.1f;
+
+            Quaternion cameraRot = EditorApplication.SceneViewCamera.SceneObject.Rotation;
+            bottomLeft = cameraRot.Rotate(bottomLeft + offset);
+            topLeft = cameraRot.Rotate(topLeft + offset);
+            topRight = cameraRot.Rotate(topRight + offset);
+            bottomRight = cameraRot.Rotate(bottomRight + offset);
+
+            HandleDrawing.DrawLine(bottomLeft, bottomRight, handleSize);
+            HandleDrawing.DrawLine(bottomLeft, topLeft, handleSize);
+            HandleDrawing.DrawLine(topLeft, topRight, handleSize);
+            HandleDrawing.DrawLine(bottomRight, topRight, handleSize);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's x axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's x axis in world space</returns>
+        private Vector3 GetXDir()
+        {
+            return rotation.Rotate(Vector3.XAxis);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's y axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's y axis in world space</returns>
+        private Vector3 GetYDir()
+        {
+            return rotation.Rotate(Vector3.YAxis);
+        }
+
+        /// <summary>
+        /// Returns the direction of the handle's z axis in world space.
+        /// </summary>
+        /// <returns>Direction of the handle's z axis in world space</returns>
+        private Vector3 GetZDir()
+        {
+            return rotation.Rotate(Vector3.ZAxis);
+        }
+    }
+}

+ 8 - 4
MBansheeEditor/Scene/SceneAxesHandle.cs

@@ -8,8 +8,10 @@ namespace BansheeEditor
     /// one of the axes, or change projection modes.
     /// </summary>
     [CustomHandle(null)]
-    public class SceneAxesHandle : Handle
+    internal class SceneAxesHandle : Handle
     {
+        public const UInt64 LAYER = 0x7000000000000000;
+
         private const float CONE_HEIGHT = 0.25f;
         private const float CONE_RADIUS = 0.175f;
 
@@ -28,9 +30,9 @@ namespace BansheeEditor
         /// </summary>
         public SceneAxesHandle()
         {
-            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f);
-            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f);
-            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f);
+            xAxis = new HandleSliderLine(this, Vector3.XAxis, 1.0f, true, LAYER);
+            yAxis = new HandleSliderLine(this, Vector3.YAxis, 1.0f, true, LAYER);
+            zAxis = new HandleSliderLine(this, Vector3.ZAxis, 1.0f, true, LAYER);
 
             projTypePlane = new HandleSliderPlane(this, Vector3.XAxis, Vector3.YAxis, 0.4f);
         }
@@ -99,10 +101,12 @@ namespace BansheeEditor
         /// <inheritdoc/>
         protected internal override void Draw()
         {
+            HandleDrawing.Layer = LAYER;
             HandleDrawing.Transform = Matrix4.TRS(position, rotation, Vector3.One);
             Vector3 cameraForward = EditorApplication.SceneViewCamera.SceneObject.Forward;
             float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
 
+           
             // Draw 1D arrows
             Color xColor = Color.Red;
             if (xAxis.State == HandleSlider.StateType.Active)

+ 1 - 0
MBansheeEditor/Scene/SceneWindow.cs

@@ -639,6 +639,7 @@ namespace BansheeEditor
                 camera.NearClipPlane = 0.05f;
                 camera.FarClipPlane = 2500.0f;
                 camera.ClearColor = ClearColor;
+		        camera.Layers = UInt64.MaxValue & ~SceneAxesHandle.LAYER; // Don't draw scene axes in this camera
 
                 cameraController = sceneCameraSO.AddComponent<SceneCamera>();
 

+ 1 - 0
SBansheeEditor/Include/BsScriptHandleDrawing.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		static void internal_SetColor(Color* color);
 		static void internal_SetTransform(Matrix4* transform);
+		static void internal_SetLayer(UINT64 layer);
 
 		static void internal_DrawCube(Vector3* position, Vector3* extents, float size);
 		static void internal_DrawSphere(Vector3* position, float radius, float size);

+ 2 - 2
SBansheeEditor/Include/BsScriptHandleSliderDisc.h

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		virtual void destroyInternal() override;
 
 	private:
-		ScriptHandleSliderDisc(MonoObject* instance, const Vector3& normal, float radius, bool fixedScale);
+		ScriptHandleSliderDisc(MonoObject* instance, const Vector3& normal, float radius, bool fixedScale, UINT64 layer);
 		~ScriptHandleSliderDisc();
 
 		HandleSliderDisc* mSlider;
@@ -36,7 +36,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
-		static void internal_CreateInstance(MonoObject* instance, Vector3* normal, float radius, bool fixedScale);
+		static void internal_CreateInstance(MonoObject* instance, Vector3* normal, float radius, bool fixedScale, UINT64 layer);
 		static void internal_GetDelta(ScriptHandleSliderDisc* nativeInstance, float* value);
 		static void internal_GetStartAngle(ScriptHandleSliderDisc* nativeInstance, float* value);
 		static void internal_SetCutoffPlane(ScriptHandleSliderDisc* nativeInstance, float value, bool enabled);

+ 2 - 2
SBansheeEditor/Include/BsScriptHandleSliderLine.h

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		virtual void destroyInternal() override;
 
 	private:
-		ScriptHandleSliderLine(MonoObject* instance, const Vector3& direction, float length, bool fixedScale);
+		ScriptHandleSliderLine(MonoObject* instance, const Vector3& direction, float length, bool fixedScale, UINT64 layer);
 		~ScriptHandleSliderLine();
 
 		HandleSliderLine* mSlider;
@@ -36,7 +36,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
-		static void internal_CreateInstance(MonoObject* instance, Vector3* direction, float length, bool fixedScale);
+		static void internal_CreateInstance(MonoObject* instance, Vector3* direction, float length, bool fixedScale, UINT64 layer);
 		static void internal_GetDelta(ScriptHandleSliderLine* nativeInstance, float* value);
 	};
 }

+ 4 - 2
SBansheeEditor/Include/BsScriptHandleSliderPlane.h

@@ -28,7 +28,8 @@ namespace BansheeEngine
 		virtual void destroyInternal() override;
 
 	private:
-		ScriptHandleSliderPlane(MonoObject* instance, const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale);
+		ScriptHandleSliderPlane(MonoObject* instance, const Vector3& dir1, const Vector3& dir2, float length, 
+			bool fixedScale, UINT64 layer);
 		~ScriptHandleSliderPlane();
 
 		HandleSliderPlane* mSlider;
@@ -36,7 +37,8 @@ namespace BansheeEngine
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
-		static void internal_CreateInstance(MonoObject* instance, Vector3* dir1, Vector3* dir2, float length, bool fixedScale);
+		static void internal_CreateInstance(MonoObject* instance, Vector3* dir1, Vector3* dir2, float length, 
+			bool fixedScale, UINT64 layer);
 		static void internal_GetDelta(ScriptHandleSliderPlane* nativeInstance, Vector2* value);
 	};
 }

+ 6 - 0
SBansheeEditor/Source/BsScriptHandleDrawing.cpp

@@ -12,6 +12,7 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_SetColor", &ScriptHandleDrawing::internal_SetColor);
 		metaData.scriptClass->addInternalCall("Internal_SetTransform", &ScriptHandleDrawing::internal_SetTransform);
+		metaData.scriptClass->addInternalCall("Internal_SetLayer", &ScriptHandleDrawing::internal_SetLayer);
 		metaData.scriptClass->addInternalCall("Internal_DrawCube", &ScriptHandleDrawing::internal_DrawCube);
 		metaData.scriptClass->addInternalCall("Internal_DrawSphere", &ScriptHandleDrawing::internal_DrawSphere);
 		metaData.scriptClass->addInternalCall("Internal_DrawWireCube", &ScriptHandleDrawing::internal_DrawWireCube);
@@ -35,6 +36,11 @@ namespace BansheeEngine
 		HandleManager::instance().getDrawManager().setTransform(*transform);
 	}
 
+	void ScriptHandleDrawing::internal_SetLayer(UINT64 layer)
+	{
+		HandleManager::instance().getDrawManager().setLayer(layer);
+	}
+
 	void ScriptHandleDrawing::internal_DrawCube(Vector3* position, Vector3* extents, float size)
 	{
 		HandleManager::instance().getDrawManager().drawCube(*position, *extents, size);

+ 4 - 4
SBansheeEditor/Source/BsScriptHandleSliderDisc.cpp

@@ -6,10 +6,10 @@
 
 namespace BansheeEngine
 {
-	ScriptHandleSliderDisc::ScriptHandleSliderDisc(MonoObject* instance, const Vector3& normal, float radius, bool fixedScale)
+	ScriptHandleSliderDisc::ScriptHandleSliderDisc(MonoObject* instance, const Vector3& normal, float radius, bool fixedScale, UINT64 layer)
 		:ScriptObject(instance), mSlider(nullptr)
 	{
-		mSlider = bs_new<HandleSliderDisc>(normal, radius, fixedScale);
+		mSlider = bs_new<HandleSliderDisc>(normal, radius, fixedScale, layer);
 	}
 
 	ScriptHandleSliderDisc::~ScriptHandleSliderDisc()
@@ -34,10 +34,10 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetCutoffPlane", &ScriptHandleSliderDisc::internal_SetCutoffPlane);
 	}
 
-	void ScriptHandleSliderDisc::internal_CreateInstance(MonoObject* instance, Vector3* normal, float radius, bool fixedScale)
+	void ScriptHandleSliderDisc::internal_CreateInstance(MonoObject* instance, Vector3* normal, float radius, bool fixedScale, UINT64 layer)
 	{
 		ScriptHandleSliderDisc* nativeInstance = new (bs_alloc<ScriptHandleSliderDisc>())
-			ScriptHandleSliderDisc(instance, *normal, radius, fixedScale);
+			ScriptHandleSliderDisc(instance, *normal, radius, fixedScale, layer);
 	}
 
 	void ScriptHandleSliderDisc::internal_GetDelta(ScriptHandleSliderDisc* nativeInstance, float* value)

+ 6 - 4
SBansheeEditor/Source/BsScriptHandleSliderLine.cpp

@@ -6,10 +6,11 @@
 
 namespace BansheeEngine
 {
-	ScriptHandleSliderLine::ScriptHandleSliderLine(MonoObject* instance, const Vector3& direction, float length, bool fixedScale)
+	ScriptHandleSliderLine::ScriptHandleSliderLine(MonoObject* instance, const Vector3& direction, float length, 
+		bool fixedScale, UINT64 layer)
 		:ScriptObject(instance), mSlider(nullptr)
 	{
-		mSlider = bs_new<HandleSliderLine>(direction, length, fixedScale);
+		mSlider = bs_new<HandleSliderLine>(direction, length, fixedScale, layer);
 	}
 
 	ScriptHandleSliderLine::~ScriptHandleSliderLine()
@@ -32,10 +33,11 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetDelta", &ScriptHandleSliderLine::internal_GetDelta);
 	}
 
-	void ScriptHandleSliderLine::internal_CreateInstance(MonoObject* instance, Vector3* direction, float length, bool fixedScale)
+	void ScriptHandleSliderLine::internal_CreateInstance(MonoObject* instance, Vector3* direction, float length, 
+		bool fixedScale, UINT64 layer)
 	{
 		ScriptHandleSliderLine* nativeInstance = new (bs_alloc<ScriptHandleSliderLine>()) 
-			ScriptHandleSliderLine(instance, *direction, length, fixedScale);
+			ScriptHandleSliderLine(instance, *direction, length, fixedScale, layer);
 	}
 
 	void ScriptHandleSliderLine::internal_GetDelta(ScriptHandleSliderLine* nativeInstance, float* value)

+ 6 - 4
SBansheeEditor/Source/BsScriptHandleSliderPlane.cpp

@@ -6,10 +6,11 @@
 
 namespace BansheeEngine
 {
-	ScriptHandleSliderPlane::ScriptHandleSliderPlane(MonoObject* instance, const Vector3& dir1, const Vector3& dir2, float length, bool fixedScale)
+	ScriptHandleSliderPlane::ScriptHandleSliderPlane(MonoObject* instance, const Vector3& dir1, const Vector3& dir2, 
+		float length, bool fixedScale, UINT64 layer)
 		:ScriptObject(instance), mSlider(nullptr)
 	{
-		mSlider = bs_new<HandleSliderPlane>(dir1, dir2, length, fixedScale);
+		mSlider = bs_new<HandleSliderPlane>(dir1, dir2, length, fixedScale, layer);
 	}
 
 	ScriptHandleSliderPlane::~ScriptHandleSliderPlane()
@@ -32,10 +33,11 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetDelta", &ScriptHandleSliderPlane::internal_GetDelta);
 	}
 
-	void ScriptHandleSliderPlane::internal_CreateInstance(MonoObject* instance, Vector3* dir1, Vector3* dir2, float length, bool fixedScale)
+	void ScriptHandleSliderPlane::internal_CreateInstance(MonoObject* instance, Vector3* dir1, Vector3* dir2, 
+		float length, bool fixedScale, UINT64 layer)
 	{
 		ScriptHandleSliderPlane* nativeInstance = new (bs_alloc<ScriptHandleSliderPlane>())
-			ScriptHandleSliderPlane(instance, *dir1, *dir2, length, fixedScale);
+			ScriptHandleSliderPlane(instance, *dir1, *dir2, length, fixedScale, layer);
 	}
 
 	void ScriptHandleSliderPlane::internal_GetDelta(ScriptHandleSliderPlane* nativeInstance, Vector2* value)