Просмотр исходного кода

Calling Managed OnInitialize/OnEnable/etc methods will now properly call them if they're defined on a base class
Initializing PhysX objects now provides identity instead of zero transforms
When entering play mode properly trigger OnEnable event
OnInitialize even will now trigger even when the game is paused, because I can't think of a reason not to and implementation is simpler
Enforcing constraints on contact & rest offset for colliders
Fixed frame allocator so it properly aligns memory when it is requested

BearishSun 9 лет назад
Родитель
Сommit
3fa4d3de58
25 измененных файлов с 6305 добавлено и 6268 удалено
  1. 187 187
      Source/BansheeCore/Include/BsCCollider.h
  2. 113 109
      Source/BansheeCore/Include/BsFCollider.h
  3. 6 1
      Source/BansheeCore/Source/BsCCollider.cpp
  4. 388 386
      Source/BansheeCore/Source/BsCoreApplication.cpp
  5. 188 188
      Source/BansheePhysX/Source/BsFPhysXCollider.cpp
  6. 282 282
      Source/BansheePhysX/Source/BsPhysXD6Joint.cpp
  7. 101 101
      Source/BansheePhysX/Source/BsPhysXDistanceJoint.cpp
  8. 22 22
      Source/BansheePhysX/Source/BsPhysXFixedJoint.cpp
  9. 104 104
      Source/BansheePhysX/Source/BsPhysXHingeJoint.cpp
  10. 84 84
      Source/BansheePhysX/Source/BsPhysXSliderJoint.cpp
  11. 292 285
      Source/BansheeUtility/Source/BsFrameAlloc.cpp
  12. 176 176
      Source/MBansheeEditor/AboutBox.cs
  13. 621 621
      Source/MBansheeEditor/MenuItems.cs
  14. 108 108
      Source/MBansheeEngine/Component.cs
  15. 799 799
      Source/MBansheeEngine/Math/Quaternion.cs
  16. 15 8
      Source/MBansheeEngine/Physics/Collider.cs
  17. 300 300
      Source/MBansheeEngine/Physics/D6Joint.cs
  18. 802 802
      Source/MBansheeEngine/Physics/Rigidbody.cs
  19. 584 583
      Source/MBansheeEngine/SceneObject.cs
  20. 167 161
      Source/SBansheeEngine/Include/BsManagedComponent.h
  21. 107 127
      Source/SBansheeEngine/Include/BsScriptGameObjectManager.h
  22. 428 393
      Source/SBansheeEngine/Source/BsManagedComponent.cpp
  23. 131 135
      Source/SBansheeEngine/Source/BsPlayInEditorManager.cpp
  24. 194 200
      Source/SBansheeEngine/Source/BsScriptGameObjectManager.cpp
  25. 106 106
      Source/SBansheeEngine/Source/BsScriptObjectManager.cpp

+ 187 - 187
Source/BansheeCore/Include/BsCCollider.h

@@ -1,188 +1,188 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsCollider.h"
-#include "BsComponent.h"
-
-namespace BansheeEngine 
-{
-	/** @addtogroup Components-Core
-	 *  @{
-	 */
-
-	/**
-	 * @copydoc	Collider
-	 *
-	 * Wraps Collider as a Component.
-	 */
-    class BS_CORE_EXPORT CCollider : public Component
-    {
-    public:
-		CCollider(const HSceneObject& parent);
-		virtual ~CCollider() {}
-
-		/** @copydoc Collider::setIsTrigger */
-		inline void setIsTrigger(bool value);
-
-		/** @copydoc Collider::getIsTrigger */
-		bool getIsTrigger() const { return mIsTrigger; }
-
-		/** @copydoc Collider::setMass */
-		inline void setMass(float mass);
-
-		/** @copydoc Collider::getMass */
-		float getMass() const { return mMass; }
-
-		/** @copydoc Collider::setMaterial */
-		inline void setMaterial(const HPhysicsMaterial& material);
-
-		/** @copydoc Collider::getMaterial */
-		HPhysicsMaterial getMaterial() const { return mMaterial; }
-
-		/** @copydoc Collider::setContactOffset */
-		inline void setContactOffset(float value);
-
-		/** @copydoc Collider::getContactOffset */
-		float getContactOffset() const { return mContactOffset; }
-
-		/** @copydoc Collider::setRestOffset */
-		inline void setRestOffset(float value);
-
-		/** @copydoc Collider::getRestOffset */
-		float getRestOffset() const { return mRestOffset; }
-
-		/** @copydoc Collider::setLayer */
-		inline void setLayer(UINT64 layer);
-
-		/** @copydoc Collider::getLayer */
-		UINT64 getLayer() const { return mLayer; }
-
-		/** @copydoc Collider::setCollisionReportMode */
-		inline void setCollisionReportMode(CollisionReportMode mode);
-
-		/** @copydoc Collider::getCollisionReportMode */
-		CollisionReportMode getCollisionReportMode() const { return mCollisionReportMode; }
-
-		/** @copydoc Collider::getRigidbody */
-		HRigidbody getRigidbody() const { return mParent; }
-
-		/** @copydoc Collider::rayCast(const Ray&, PhysicsQueryHit&, float) */
-		inline bool rayCast(const Ray& ray, PhysicsQueryHit& hit, float maxDist = FLT_MAX) const;
-
-		/** @copydoc Collider::rayCast(const Vector3&, const Vector3&, PhysicsQueryHit&, float) */
-		inline bool rayCast(const Vector3& origin, const Vector3& unitDir, PhysicsQueryHit& hit,
-			float maxDist = FLT_MAX) const;
-
-		/** @copydoc Collider::onCollisionBegin */
-		Event<void(const CollisionData&)> onCollisionBegin;
-
-		/** @copydoc Collider::onCollisionStay */
-		Event<void(const CollisionData&)> onCollisionStay;
-
-		/** @copydoc Collider::onCollisionEnd */
-		Event<void(const CollisionData&)> onCollisionEnd;
-
-		/** @cond INTERNAL */
-
-		/** Returns the Collider implementation wrapped by this component. */
-		Collider* _getInternal() const { return mInternal.get(); }
-
-		/** @endcond */
-
-		/************************************************************************/
-		/* 						COMPONENT OVERRIDES                      		*/
-		/************************************************************************/
-	protected:
-		friend class SceneObject;
-		friend class CRigidbody;
-
-		/** @copydoc Component::onInitialized() */
-		void onInitialized() override;
-
-		/** @copydoc Component::onDestroyed() */
-		void onDestroyed() override;
-
-		/** @copydoc Component::onDisabled() */
-		void onDisabled() override;
-
-		/** @copydoc Component::onEnabled() */
-		void onEnabled() override;
-
-		/** @copydoc Component::onTransformChanged() */
-		void onTransformChanged(TransformChangedFlags flags) override;
-
-    protected:
-		/** Creates the internal representation of the Collider for use by the component. */
-		virtual SPtr<Collider> createInternal() = 0;
-
-		/** Creates the internal representation of the Collider and restores the values saved by the Component. */
-		virtual void restoreInternal();
-
-		/** Destroys the internal collider representation. */
-		void destroyInternal();
-
-		/** 
-		 * Checks is the provided rigidbody a valid parent for this collider. 
-		 *
-		 * @note This is required because certain colliders are limited in how they can be used. */
-		virtual bool isValidParent(const HRigidbody& parent) const { return true; }
-
-		/**
-		 * Changes the rigidbody parent of the collider. Meant to be called from the Rigidbody itself. 
-		 *
-		 * @param rigidbody	New rigidbody to assign as the parent to the collider.
-		 * @param internal	If true the rigidbody will just be changed internally, but parent rigidbody will not be
-		 *                  notified.
-		 */
-		void setRigidbody(const HRigidbody& rigidbody, bool internal = false);
-
-		/** 
-		 * Updates the transform of the internal Collider representation from the transform of the component's scene object.
-		 */
-		void updateTransform();
-
-		/** Applies the collision report mode to the internal collider depending on the current state. */
-		void updateCollisionReportMode();
-
-		/** Searches the parent scene object hierarchy to find a parent Rigidbody component. */
-		void updateParentRigidbody();
-
-		/** Triggered when the internal collider begins touching another object. */
-		void triggerOnCollisionBegin(const CollisionData& data);
-
-		/** Triggered when the internal collider continues touching another object. */
-		void triggerOnCollisionStay(const CollisionData& data);
-
-		/** Triggered when the internal collider ends touching another object. */
-		void triggerOnCollisionEnd(const CollisionData& data);
-
-		SPtr<Collider> mInternal;
-
-		UINT64 mLayer = 1;
-		CollisionReportMode mCollisionReportMode = CollisionReportMode::None;
-		float mRestOffset = 0.0f;
-		float mContactOffset = 0.0f;
-		HPhysicsMaterial mMaterial;
-		float mMass = 0.0f;
-		bool mIsTrigger = false;
-		Vector3 mLocalPosition;
-		Quaternion mLocalRotation;
-
-		HRigidbody mParent;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class CColliderRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		RTTITypeBase* getRTTI() const override;
-
-	protected:
-		CCollider() {} // Serialization only
-     };
-
-	 /** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsCollider.h"
+#include "BsComponent.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup Components-Core
+	 *  @{
+	 */
+
+	/**
+	 * @copydoc	Collider
+	 *
+	 * Wraps Collider as a Component.
+	 */
+    class BS_CORE_EXPORT CCollider : public Component
+    {
+    public:
+		CCollider(const HSceneObject& parent);
+		virtual ~CCollider() {}
+
+		/** @copydoc Collider::setIsTrigger */
+		inline void setIsTrigger(bool value);
+
+		/** @copydoc Collider::getIsTrigger */
+		bool getIsTrigger() const { return mIsTrigger; }
+
+		/** @copydoc Collider::setMass */
+		inline void setMass(float mass);
+
+		/** @copydoc Collider::getMass */
+		float getMass() const { return mMass; }
+
+		/** @copydoc Collider::setMaterial */
+		inline void setMaterial(const HPhysicsMaterial& material);
+
+		/** @copydoc Collider::getMaterial */
+		HPhysicsMaterial getMaterial() const { return mMaterial; }
+
+		/** @copydoc Collider::setContactOffset */
+		inline void setContactOffset(float value);
+
+		/** @copydoc Collider::getContactOffset */
+		float getContactOffset() const { return mContactOffset; }
+
+		/** @copydoc Collider::setRestOffset */
+		inline void setRestOffset(float value);
+
+		/** @copydoc Collider::getRestOffset */
+		float getRestOffset() const { return mRestOffset; }
+
+		/** @copydoc Collider::setLayer */
+		inline void setLayer(UINT64 layer);
+
+		/** @copydoc Collider::getLayer */
+		UINT64 getLayer() const { return mLayer; }
+
+		/** @copydoc Collider::setCollisionReportMode */
+		inline void setCollisionReportMode(CollisionReportMode mode);
+
+		/** @copydoc Collider::getCollisionReportMode */
+		CollisionReportMode getCollisionReportMode() const { return mCollisionReportMode; }
+
+		/** @copydoc Collider::getRigidbody */
+		HRigidbody getRigidbody() const { return mParent; }
+
+		/** @copydoc Collider::rayCast(const Ray&, PhysicsQueryHit&, float) */
+		inline bool rayCast(const Ray& ray, PhysicsQueryHit& hit, float maxDist = FLT_MAX) const;
+
+		/** @copydoc Collider::rayCast(const Vector3&, const Vector3&, PhysicsQueryHit&, float) */
+		inline bool rayCast(const Vector3& origin, const Vector3& unitDir, PhysicsQueryHit& hit,
+			float maxDist = FLT_MAX) const;
+
+		/** @copydoc Collider::onCollisionBegin */
+		Event<void(const CollisionData&)> onCollisionBegin;
+
+		/** @copydoc Collider::onCollisionStay */
+		Event<void(const CollisionData&)> onCollisionStay;
+
+		/** @copydoc Collider::onCollisionEnd */
+		Event<void(const CollisionData&)> onCollisionEnd;
+
+		/** @cond INTERNAL */
+
+		/** Returns the Collider implementation wrapped by this component. */
+		Collider* _getInternal() const { return mInternal.get(); }
+
+		/** @endcond */
+
+		/************************************************************************/
+		/* 						COMPONENT OVERRIDES                      		*/
+		/************************************************************************/
+	protected:
+		friend class SceneObject;
+		friend class CRigidbody;
+
+		/** @copydoc Component::onInitialized() */
+		void onInitialized() override;
+
+		/** @copydoc Component::onDestroyed() */
+		void onDestroyed() override;
+
+		/** @copydoc Component::onDisabled() */
+		void onDisabled() override;
+
+		/** @copydoc Component::onEnabled() */
+		void onEnabled() override;
+
+		/** @copydoc Component::onTransformChanged() */
+		void onTransformChanged(TransformChangedFlags flags) override;
+
+    protected:
+		/** Creates the internal representation of the Collider for use by the component. */
+		virtual SPtr<Collider> createInternal() = 0;
+
+		/** Creates the internal representation of the Collider and restores the values saved by the Component. */
+		virtual void restoreInternal();
+
+		/** Destroys the internal collider representation. */
+		void destroyInternal();
+
+		/** 
+		 * Checks is the provided rigidbody a valid parent for this collider. 
+		 *
+		 * @note This is required because certain colliders are limited in how they can be used. */
+		virtual bool isValidParent(const HRigidbody& parent) const { return true; }
+
+		/**
+		 * Changes the rigidbody parent of the collider. Meant to be called from the Rigidbody itself. 
+		 *
+		 * @param rigidbody	New rigidbody to assign as the parent to the collider.
+		 * @param internal	If true the rigidbody will just be changed internally, but parent rigidbody will not be
+		 *                  notified.
+		 */
+		void setRigidbody(const HRigidbody& rigidbody, bool internal = false);
+
+		/** 
+		 * Updates the transform of the internal Collider representation from the transform of the component's scene object.
+		 */
+		void updateTransform();
+
+		/** Applies the collision report mode to the internal collider depending on the current state. */
+		void updateCollisionReportMode();
+
+		/** Searches the parent scene object hierarchy to find a parent Rigidbody component. */
+		void updateParentRigidbody();
+
+		/** Triggered when the internal collider begins touching another object. */
+		void triggerOnCollisionBegin(const CollisionData& data);
+
+		/** Triggered when the internal collider continues touching another object. */
+		void triggerOnCollisionStay(const CollisionData& data);
+
+		/** Triggered when the internal collider ends touching another object. */
+		void triggerOnCollisionEnd(const CollisionData& data);
+
+		SPtr<Collider> mInternal;
+
+		UINT64 mLayer = 1;
+		CollisionReportMode mCollisionReportMode = CollisionReportMode::None;
+		float mRestOffset = 0.0f;
+		float mContactOffset = 0.02f;
+		HPhysicsMaterial mMaterial;
+		float mMass = 1.0f;
+		bool mIsTrigger = false;
+		Vector3 mLocalPosition;
+		Quaternion mLocalRotation;
+
+		HRigidbody mParent;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class CColliderRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+
+	protected:
+		CCollider() {} // Serialization only
+     };
+
+	 /** @} */
 }

+ 113 - 109
Source/BansheeCore/Include/BsFCollider.h

@@ -1,110 +1,114 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsPhysicsCommon.h"
-#include "BsVector3.h"
-#include "BsQuaternion.h"
-
-namespace BansheeEngine
-{
-	/** @cond INTERNAL */
-	/** @addtogroup Physics
-	 *  @{
-	 */
-
-	/** Provides common functionality used by all Collider types. */
-	class BS_CORE_EXPORT FCollider
-	{
-	public:
-		virtual ~FCollider();
-
-		/** Returns the position of the collider. */
-		virtual Vector3 getPosition() const = 0;
-
-		/** Returns the rotation of the collider. */
-		virtual Quaternion getRotation() const = 0;
-
-		/** Sets the position and rotation of the collider. */
-		virtual void setTransform(const Vector3& pos, const Quaternion& rotation) = 0;
-
-		/** 
-		 * Enables/disables a collider as a trigger. A trigger will not be used for collisions (i.e. objects will pass 
-		 * through it), but collision events will still be reported. 
-		 */
-		virtual void setIsTrigger(bool value) = 0;
-
-		/** Checks is the collider a trigger. */
-		virtual bool getIsTrigger() const = 0;
-
-		/** 
-		 * Changes whether the collider is a part of a rigidbody (non-static), or is on its own (static). You should change
-		 * this whenever you are attaching or detaching a collider from a rigidbody.
-		 */
-		virtual void setIsStatic(bool value) = 0;
-
-		/** Checks whether the collider is a part of a rigidbody (non-static), or is on its own (static). */
-		virtual bool getIsStatic() const = 0;
-
-		/** 
-		 * Sets the mass of the collider. Only relevant if the collider is part of a rigidbody. Ultimately this will
-		 * determine the total mass, center of mass and inertia tensors of the parent rigidbody (if they're being calculated
-		 * automatically).
-		 */
-		virtual void setMass(float mass) { mMass = mass; }
-
-		/** Returns the mass of the collider. */
-		virtual float getMass() const { return mMass; }
-
-		/** Sets the material of the collider. The material determines how objects hitting the collider behave. */
-		virtual void setMaterial(const HPhysicsMaterial& material);
-
-		/** Gets the material of the collider. The material determines how objects hitting the collider behave. */
-		virtual HPhysicsMaterial getMaterial() const { return mMaterial; }
-
-		/**
-		 * Determines how far apart do two shapes need to be away from each other before the physics runtime starts 
-		 * generating repelling impulse for them. This distance will be the sum of contact offsets of the two interacting
-		 * objects. If objects are moving fast you can increase this value to start generating the impulse earlier and 
-		 * potentially prevent the objects from interpenetrating. This value is in meters.
-		 *
-		 * Also see setRestOffset().
-		 */
-		virtual void setContactOffset(float value) = 0;
-
-		/** Returns shape's contact offset in meters. See setContactOffset() to learn contact offset is. */
-		virtual float getContactOffset() const = 0;
-
-		/**
-		 * Sets at what distance should two objects resting on one another come to an equilibrium. The value used in the
-		 * runtime will be the sum of rest offsets for both interacting objects. This value is in meters.
-		 */
-		virtual void setRestOffset(float value) = 0;
-
-		/** Returns shepe's rest offset in meters. See setRestOffset() to learn what contact offset is. */
-		virtual float getRestOffset() const = 0;
-
-		/** Sets the layer of the collider. Layer controls with which objects will the collider collide. */
-		virtual void setLayer(UINT64 layer) = 0;
-
-		/** Gets the layer of the collider. Layer controls with which objects will the collider collide. */
-		virtual UINT64 getLayer() const = 0;
-
-		/** Sets a value that determines which (if any) collision events are reported. */
-		virtual void setCollisionReportMode(CollisionReportMode mode) = 0;
-
-		/** Gets a value that determines which (if any) collision events are reported. */
-		virtual CollisionReportMode getCollisionReportMode() const = 0;
-
-		/** Enables continous collision detect for this collider. Only valid if the collider is a part of a rigidbody. */
-		virtual void _setCCD(bool enabled) = 0;
-	protected:
-		float mMass = 1.0f;
-		
-		HPhysicsMaterial mMaterial;
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsPhysicsCommon.h"
+#include "BsVector3.h"
+#include "BsQuaternion.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Physics
+	 *  @{
+	 */
+
+	/** Provides common functionality used by all Collider types. */
+	class BS_CORE_EXPORT FCollider
+	{
+	public:
+		virtual ~FCollider();
+
+		/** Returns the position of the collider. */
+		virtual Vector3 getPosition() const = 0;
+
+		/** Returns the rotation of the collider. */
+		virtual Quaternion getRotation() const = 0;
+
+		/** Sets the position and rotation of the collider. */
+		virtual void setTransform(const Vector3& pos, const Quaternion& rotation) = 0;
+
+		/** 
+		 * Enables/disables a collider as a trigger. A trigger will not be used for collisions (i.e. objects will pass 
+		 * through it), but collision events will still be reported. 
+		 */
+		virtual void setIsTrigger(bool value) = 0;
+
+		/** Checks is the collider a trigger. */
+		virtual bool getIsTrigger() const = 0;
+
+		/** 
+		 * Changes whether the collider is a part of a rigidbody (non-static), or is on its own (static). You should change
+		 * this whenever you are attaching or detaching a collider from a rigidbody.
+		 */
+		virtual void setIsStatic(bool value) = 0;
+
+		/** Checks whether the collider is a part of a rigidbody (non-static), or is on its own (static). */
+		virtual bool getIsStatic() const = 0;
+
+		/** 
+		 * Sets the mass of the collider. Only relevant if the collider is part of a rigidbody. Ultimately this will
+		 * determine the total mass, center of mass and inertia tensors of the parent rigidbody (if they're being calculated
+		 * automatically).
+		 */
+		virtual void setMass(float mass) { mMass = mass; }
+
+		/** Returns the mass of the collider. */
+		virtual float getMass() const { return mMass; }
+
+		/** Sets the material of the collider. The material determines how objects hitting the collider behave. */
+		virtual void setMaterial(const HPhysicsMaterial& material);
+
+		/** Gets the material of the collider. The material determines how objects hitting the collider behave. */
+		virtual HPhysicsMaterial getMaterial() const { return mMaterial; }
+
+		/**
+		 * Determines how far apart do two shapes need to be away from each other before the physics runtime starts 
+		 * generating repelling impulse for them. This distance will be the sum of contact offsets of the two interacting
+		 * objects. If objects are moving fast you can increase this value to start generating the impulse earlier and 
+		 * potentially prevent the objects from interpenetrating. This value is in meters. Must be positive and greater
+		 * than rest offset.
+		 *
+		 * Also see setRestOffset().
+		 */
+		virtual void setContactOffset(float value) = 0;
+
+		/** Returns shape's contact offset in meters. See setContactOffset() to learn contact offset is. */
+		virtual float getContactOffset() const = 0;
+
+		/**
+		 * Sets at what distance should two objects resting on one another come to an equilibrium. The value used in the
+		 * runtime will be the sum of rest offsets for both interacting objects. This value is in meters. Cannot be larger
+		 * than contact offset.
+		 *
+		 * Also see setContactOffset().
+		 */
+		virtual void setRestOffset(float value) = 0;
+
+		/** Returns shepe's rest offset in meters. See setRestOffset() to learn what contact offset is. */
+		virtual float getRestOffset() const = 0;
+
+		/** Sets the layer of the collider. Layer controls with which objects will the collider collide. */
+		virtual void setLayer(UINT64 layer) = 0;
+
+		/** Gets the layer of the collider. Layer controls with which objects will the collider collide. */
+		virtual UINT64 getLayer() const = 0;
+
+		/** Sets a value that determines which (if any) collision events are reported. */
+		virtual void setCollisionReportMode(CollisionReportMode mode) = 0;
+
+		/** Gets a value that determines which (if any) collision events are reported. */
+		virtual CollisionReportMode getCollisionReportMode() const = 0;
+
+		/** Enables continous collision detect for this collider. Only valid if the collider is a part of a rigidbody. */
+		virtual void _setCCD(bool enabled) = 0;
+	protected:
+		float mMass = 1.0f;
+		
+		HPhysicsMaterial mMaterial;
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 6 - 1
Source/BansheeCore/Source/BsCCollider.cpp

@@ -60,6 +60,8 @@ namespace BansheeEngine
 
 	void CCollider::setContactOffset(float value)
 	{
+		value = std::max(0.0f, std::max(value, getRestOffset()));
+
 		mContactOffset = value;
 
 		if (mInternal != nullptr)
@@ -68,6 +70,8 @@ namespace BansheeEngine
 
 	void CCollider::setRestOffset(float value)
 	{
+		value = std::min(value, getContactOffset());
+
 		mRestOffset = value;
 
 		if (mInternal != nullptr)
@@ -282,7 +286,8 @@ namespace BansheeEngine
 		if (mParent != nullptr)
 			mode = mParent->getCollisionReportMode();
 
-		mInternal->setCollisionReportMode(mode);
+		if(mInternal != nullptr)
+			mInternal->setCollisionReportMode(mode);
 	}
 
 	void CCollider::triggerOnCollisionBegin(const CollisionData& data)

+ 388 - 386
Source/BansheeCore/Source/BsCoreApplication.cpp

@@ -1,387 +1,389 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsCoreApplication.h"
-
-#include "BsRenderAPI.h"
-#include "BsRenderAPIManager.h"
-
-#include "BsPlatform.h"
-#include "BsHardwareBufferManager.h"
-#include "BsRenderWindow.h"
-#include "BsViewport.h"
-#include "BsVector2.h"
-#include "BsGpuProgram.h"
-#include "BsCoreObjectManager.h"
-#include "BsGameObjectManager.h"
-#include "BsDynLib.h"
-#include "BsDynLibManager.h"
-#include "BsCoreSceneManager.h"
-#include "BsImporter.h"
-#include "BsResources.h"
-#include "BsMesh.h"
-#include "BsSceneObject.h"
-#include "BsTime.h"
-#include "BsInput.h"
-#include "BsRendererManager.h"
-#include "BsGpuProgramManager.h"
-#include "BsMeshManager.h"
-#include "BsMaterialManager.h"
-#include "BsFontManager.h"
-#include "BsRenderWindowManager.h"
-#include "BsCoreRenderer.h"
-#include "BsDeferredCallManager.h"
-#include "BsCoreThread.h"
-#include "BsStringTableManager.h"
-#include "BsProfilingManager.h"
-#include "BsProfilerCPU.h"
-#include "BsProfilerGPU.h"
-#include "BsQueryManager.h"
-#include "BsThreadPool.h"
-#include "BsTaskScheduler.h"
-#include "BsRenderStats.h"
-#include "BsMessageHandler.h"
-#include "BsResourceListenerManager.h"
-#include "BsRenderStateManager.h"
-#include "BsShaderManager.h"
-#include "BsPhysicsManager.h"
-
-namespace BansheeEngine
-{
-	CoreApplication::CoreApplication(START_UP_DESC desc)
-		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), mLastFrameTime(0),
-		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc), mFrameStep(16666)
-	{ }
-
-	CoreApplication::~CoreApplication()
-	{
-		mPrimaryWindow->destroy();
-		mPrimaryWindow = nullptr;
-
-		PhysicsManager::shutDown();
-		Importer::shutDown();
-		FontManager::shutDown();
-		MaterialManager::shutDown();
-		MeshManager::shutDown();
-		ProfilerGPU::shutDown();
-
-		CoreSceneManager::shutDown();
-		
-		Input::shutDown();
-
-		StringTableManager::shutDown();
-		Resources::shutDown();
-		ResourceListenerManager::shutDown();
-		GameObjectManager::shutDown();
-		RenderStateManager::shutDown();
-
-		RendererManager::shutDown();
-
-		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
-		// we need to wait for those objects to get destroyed before continuing.
-		CoreObjectManager::instance().clearDirty();
-		gCoreThread().update();
-		gCoreThread().submitAccessors(true);
-
-		unloadPlugin(mRendererPlugin);
-
-		RenderAPIManager::shutDown();
-		GpuProgramCoreManager::shutDown();
-		GpuProgramManager::shutDown();
-
-		CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
-		DynLibManager::shutDown();
-		Time::shutDown();
-		DeferredCallManager::shutDown();
-
-		CoreThread::shutDown();
-		RenderStats::shutDown();
-		TaskScheduler::shutDown();
-		ThreadPool::shutDown();
-		ProfilingManager::shutDown();
-		ProfilerCPU::shutDown();
-		MessageHandler::shutDown();
-		ShaderManager::shutDown();
-
-		MemStack::endThread();
-		Platform::_shutDown();
-	}
-
-	void CoreApplication::onStartUp()
-	{
-		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
-
-		Platform::_startUp();
-		MemStack::beginThread();
-
-		ShaderManager::startUp(getShaderIncludeHandler());
-		MessageHandler::startUp();
-		ProfilerCPU::startUp();
-		ProfilingManager::startUp();
-		ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
-		TaskScheduler::startUp();
-		TaskScheduler::instance().removeWorker();
-		RenderStats::startUp();
-		CoreThread::startUp();
-		StringTableManager::startUp();
-		DeferredCallManager::startUp();
-		Time::startUp();
-		DynLibManager::startUp();
-		CoreObjectManager::startUp();
-		GameObjectManager::startUp();
-		Resources::startUp();
-		ResourceListenerManager::startUp();
-		GpuProgramManager::startUp();
-		RenderStateManager::startUp();
-		GpuProgramCoreManager::startUp();
-		RenderAPIManager::startUp();
-
-		mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
-
-		Input::startUp();
-		RendererManager::startUp();
-
-		loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
-
-		SceneManagerFactory::create();
-		RendererManager::instance().setActive(mStartUpDesc.renderer);
-		startUpRenderer();
-
-		ProfilerGPU::startUp();
-		MeshManager::startUp();
-		MaterialManager::startUp();
-		FontManager::startUp();
-		Importer::startUp();
-		PhysicsManager::startUp(mStartUpDesc.physics, isEditor());
-
-		for (auto& importerName : mStartUpDesc.importers)
-			loadPlugin(importerName);
-
-		loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
-	}
-
-	void CoreApplication::runMainLoop()
-	{
-		mRunMainLoop = true;
-
-		gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
-		while(mRunMainLoop)
-		{
-			// Limit FPS if needed
-			if (mFrameStep > 0)
-			{
-				UINT64 currentTime = gTime().getTimePrecise();
-				UINT64 nextFrameTime = mLastFrameTime + mFrameStep;
-				while (nextFrameTime > currentTime)
-				{
-					UINT32 waitTime = (UINT32)(nextFrameTime - currentTime);
-
-					// If waiting for longer, sleep
-					if (waitTime >= 2000)
-					{
-						Platform::sleep(waitTime / 1000);
-						currentTime = gTime().getTimePrecise();
-					}
-					else
-					{
-						// Otherwise we just spin, sleep timer granularity is too low and we might end up wasting a 
-						// millisecond otherwise. 
-						// Note: For mobiles where power might be more important than input latency, consider using sleep.
-						while(nextFrameTime > currentTime)
-							currentTime = gTime().getTimePrecise();
-					}
-				}
-
-				mLastFrameTime = currentTime;
-			}
-
-			gProfilerCPU().beginThread("Sim");
-
-			Platform::_update();
-			DeferredCallManager::instance()._update();
-			gTime().update();
-			gInput()._update();
-			// RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
-			// so that all input is properly captured in case there is a focus change, and so that
-			// focus change is registered before input events are sent out (mouse press can result in code
-			// checking if a window is in focus, so it has to be up to date)
-			RenderWindowManager::instance()._update(); 
-			gInput()._triggerCallbacks();
-			gDebug()._triggerCallbacks();
-
-			preUpdate();
-
-			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
-
-			gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
-			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
-			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
-
-			// Update plugins
-			for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
-				pluginUpdateFunc.second();
-
-			postUpdate();
-
-			// Send out resource events in case any were loaded/destroyed/modified
-			ResourceListenerManager::instance().update();
-
-			gCoreSceneManager()._updateCoreObjectTransforms();
-			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
-
-			// Core and sim thread run in lockstep. This will result in a larger input latency than if I was 
-			// running just a single thread. Latency becomes worse if the core thread takes longer than sim 
-			// thread, in which case sim thread needs to wait. Optimal solution would be to get an average 
-			// difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
-			{
-				BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
-
-				while(!mIsFrameRenderingFinished)
-				{
-					TaskScheduler::instance().addWorker();
-					BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
-					TaskScheduler::instance().removeWorker();
-				}
-
-				mIsFrameRenderingFinished = false;
-			}
-
-			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
-			gCoreThread().queueCommand(&Platform::_coreUpdate);
-
-			gCoreThread().update(); 
-			gCoreThread().submitAccessors(); 
-
-			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
-
-			gProfilerCPU().endThread();
-			gProfiler()._update();
-		}
-		gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
-
-		// Wait until last core frame is finished before exiting
-		{
-			BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
-
-			while (!mIsFrameRenderingFinished)
-			{
-				TaskScheduler::instance().addWorker();
-				BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
-				TaskScheduler::instance().removeWorker();
-			}
-		}
-	}
-
-	void CoreApplication::preUpdate()
-	{
-		// Do nothing
-	}
-
-	void CoreApplication::postUpdate()
-	{
-		// Do nothing
-	}
-
-	void CoreApplication::stopMainLoop()
-	{
-		mRunMainLoop = false; // No sync primitives needed, in that rare case of 
-		// a race condition we might run the loop one extra iteration which is acceptable
-	}
-
-	void CoreApplication::quitRequested()
-	{
-		stopMainLoop();
-	}
-
-	void CoreApplication::setFPSLimit(UINT32 limit)
-	{
-		mFrameStep = (UINT64)1000000 / limit;
-	}
-
-	void CoreApplication::frameRenderingFinishedCallback()
-	{
-		BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
-
-		mIsFrameRenderingFinished = true;
-		BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
-	}
-
-	void CoreApplication::startUpRenderer()
-	{
-		RendererManager::instance().initialize();
-	}
-
-	void CoreApplication::beginCoreProfiling()
-	{
-		gProfilerCPU().beginThread("Core");
-		ProfilerGPU::instance().beginFrame();
-	}
-
-	void CoreApplication::endCoreProfiling()
-	{
-		ProfilerGPU::instance().endFrame();
-		ProfilerGPU::instance()._update();
-
-		gProfilerCPU().endThread();
-		gProfiler()._updateCore();
-	}
-
-	void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
-	{
-		DynLib* loadedLibrary = gDynLibManager().load(pluginName);
-		if(library != nullptr)
-			*library = loadedLibrary;
-
-		void* retVal = nullptr;
-		if(loadedLibrary != nullptr)
-		{
-			if (passThrough == nullptr)
-			{
-				typedef void* (*LoadPluginFunc)();
-
-				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
-
-				if (loadPluginFunc != nullptr)
-					retVal = loadPluginFunc();
-			}
-			else
-			{
-				typedef void* (*LoadPluginFunc)(void*);
-
-				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
-
-				if (loadPluginFunc != nullptr)
-					retVal = loadPluginFunc(passThrough);
-			}
-
-			UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
-
-			if (loadPluginFunc != nullptr)
-				mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
-		}
-
-		return retVal;
-	}
-
-	void CoreApplication::unloadPlugin(DynLib* library)
-	{
-		typedef void (*UnloadPluginFunc)();
-
-		UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
-
-		if(unloadPluginFunc != nullptr)
-			unloadPluginFunc();
-
-		mPluginUpdateFunctions.erase(library);
-		gDynLibManager().unload(library);
-	}
-
-	ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
-	{
-		return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
-	}
-
-	CoreApplication& gCoreApplication()
-	{
-		return CoreApplication::instance();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsCoreApplication.h"
+
+#include "BsRenderAPI.h"
+#include "BsRenderAPIManager.h"
+
+#include "BsPlatform.h"
+#include "BsHardwareBufferManager.h"
+#include "BsRenderWindow.h"
+#include "BsViewport.h"
+#include "BsVector2.h"
+#include "BsGpuProgram.h"
+#include "BsCoreObjectManager.h"
+#include "BsGameObjectManager.h"
+#include "BsDynLib.h"
+#include "BsDynLibManager.h"
+#include "BsCoreSceneManager.h"
+#include "BsImporter.h"
+#include "BsResources.h"
+#include "BsMesh.h"
+#include "BsSceneObject.h"
+#include "BsTime.h"
+#include "BsInput.h"
+#include "BsRendererManager.h"
+#include "BsGpuProgramManager.h"
+#include "BsMeshManager.h"
+#include "BsMaterialManager.h"
+#include "BsFontManager.h"
+#include "BsRenderWindowManager.h"
+#include "BsCoreRenderer.h"
+#include "BsDeferredCallManager.h"
+#include "BsCoreThread.h"
+#include "BsStringTableManager.h"
+#include "BsProfilingManager.h"
+#include "BsProfilerCPU.h"
+#include "BsProfilerGPU.h"
+#include "BsQueryManager.h"
+#include "BsThreadPool.h"
+#include "BsTaskScheduler.h"
+#include "BsRenderStats.h"
+#include "BsMessageHandler.h"
+#include "BsResourceListenerManager.h"
+#include "BsRenderStateManager.h"
+#include "BsShaderManager.h"
+#include "BsPhysicsManager.h"
+#include "BsPhysics.h"
+
+namespace BansheeEngine
+{
+	CoreApplication::CoreApplication(START_UP_DESC desc)
+		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), mLastFrameTime(0),
+		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc), mFrameStep(16666)
+	{ }
+
+	CoreApplication::~CoreApplication()
+	{
+		mPrimaryWindow->destroy();
+		mPrimaryWindow = nullptr;
+
+		PhysicsManager::shutDown();
+		Importer::shutDown();
+		FontManager::shutDown();
+		MaterialManager::shutDown();
+		MeshManager::shutDown();
+		ProfilerGPU::shutDown();
+
+		CoreSceneManager::shutDown();
+		
+		Input::shutDown();
+
+		StringTableManager::shutDown();
+		Resources::shutDown();
+		ResourceListenerManager::shutDown();
+		GameObjectManager::shutDown();
+		RenderStateManager::shutDown();
+
+		RendererManager::shutDown();
+
+		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
+		// we need to wait for those objects to get destroyed before continuing.
+		CoreObjectManager::instance().clearDirty();
+		gCoreThread().update();
+		gCoreThread().submitAccessors(true);
+
+		unloadPlugin(mRendererPlugin);
+
+		RenderAPIManager::shutDown();
+		GpuProgramCoreManager::shutDown();
+		GpuProgramManager::shutDown();
+
+		CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
+		DynLibManager::shutDown();
+		Time::shutDown();
+		DeferredCallManager::shutDown();
+
+		CoreThread::shutDown();
+		RenderStats::shutDown();
+		TaskScheduler::shutDown();
+		ThreadPool::shutDown();
+		ProfilingManager::shutDown();
+		ProfilerCPU::shutDown();
+		MessageHandler::shutDown();
+		ShaderManager::shutDown();
+
+		MemStack::endThread();
+		Platform::_shutDown();
+	}
+
+	void CoreApplication::onStartUp()
+	{
+		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
+
+		Platform::_startUp();
+		MemStack::beginThread();
+
+		ShaderManager::startUp(getShaderIncludeHandler());
+		MessageHandler::startUp();
+		ProfilerCPU::startUp();
+		ProfilingManager::startUp();
+		ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
+		TaskScheduler::startUp();
+		TaskScheduler::instance().removeWorker();
+		RenderStats::startUp();
+		CoreThread::startUp();
+		StringTableManager::startUp();
+		DeferredCallManager::startUp();
+		Time::startUp();
+		DynLibManager::startUp();
+		CoreObjectManager::startUp();
+		GameObjectManager::startUp();
+		Resources::startUp();
+		ResourceListenerManager::startUp();
+		GpuProgramManager::startUp();
+		RenderStateManager::startUp();
+		GpuProgramCoreManager::startUp();
+		RenderAPIManager::startUp();
+
+		mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
+
+		Input::startUp();
+		RendererManager::startUp();
+
+		loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
+
+		SceneManagerFactory::create();
+		RendererManager::instance().setActive(mStartUpDesc.renderer);
+		startUpRenderer();
+
+		ProfilerGPU::startUp();
+		MeshManager::startUp();
+		MaterialManager::startUp();
+		FontManager::startUp();
+		Importer::startUp();
+		PhysicsManager::startUp(mStartUpDesc.physics, isEditor());
+
+		for (auto& importerName : mStartUpDesc.importers)
+			loadPlugin(importerName);
+
+		loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
+	}
+
+	void CoreApplication::runMainLoop()
+	{
+		mRunMainLoop = true;
+
+		gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
+		while(mRunMainLoop)
+		{
+			// Limit FPS if needed
+			if (mFrameStep > 0)
+			{
+				UINT64 currentTime = gTime().getTimePrecise();
+				UINT64 nextFrameTime = mLastFrameTime + mFrameStep;
+				while (nextFrameTime > currentTime)
+				{
+					UINT32 waitTime = (UINT32)(nextFrameTime - currentTime);
+
+					// If waiting for longer, sleep
+					if (waitTime >= 2000)
+					{
+						Platform::sleep(waitTime / 1000);
+						currentTime = gTime().getTimePrecise();
+					}
+					else
+					{
+						// Otherwise we just spin, sleep timer granularity is too low and we might end up wasting a 
+						// millisecond otherwise. 
+						// Note: For mobiles where power might be more important than input latency, consider using sleep.
+						while(nextFrameTime > currentTime)
+							currentTime = gTime().getTimePrecise();
+					}
+				}
+
+				mLastFrameTime = currentTime;
+			}
+
+			gProfilerCPU().beginThread("Sim");
+
+			Platform::_update();
+			DeferredCallManager::instance()._update();
+			gTime().update();
+			gInput()._update();
+			// RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
+			// so that all input is properly captured in case there is a focus change, and so that
+			// focus change is registered before input events are sent out (mouse press can result in code
+			// checking if a window is in focus, so it has to be up to date)
+			RenderWindowManager::instance()._update(); 
+			gInput()._triggerCallbacks();
+			gDebug()._triggerCallbacks();
+
+			preUpdate();
+
+			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
+			gPhysics().update();
+
+			gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
+			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
+			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
+
+			// Update plugins
+			for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
+				pluginUpdateFunc.second();
+
+			postUpdate();
+
+			// Send out resource events in case any were loaded/destroyed/modified
+			ResourceListenerManager::instance().update();
+
+			gCoreSceneManager()._updateCoreObjectTransforms();
+			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
+
+			// Core and sim thread run in lockstep. This will result in a larger input latency than if I was 
+			// running just a single thread. Latency becomes worse if the core thread takes longer than sim 
+			// thread, in which case sim thread needs to wait. Optimal solution would be to get an average 
+			// difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
+			{
+				BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
+
+				while(!mIsFrameRenderingFinished)
+				{
+					TaskScheduler::instance().addWorker();
+					BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
+					TaskScheduler::instance().removeWorker();
+				}
+
+				mIsFrameRenderingFinished = false;
+			}
+
+			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
+			gCoreThread().queueCommand(&Platform::_coreUpdate);
+
+			gCoreThread().update(); 
+			gCoreThread().submitAccessors(); 
+
+			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
+
+			gProfilerCPU().endThread();
+			gProfiler()._update();
+		}
+		gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
+
+		// Wait until last core frame is finished before exiting
+		{
+			BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
+
+			while (!mIsFrameRenderingFinished)
+			{
+				TaskScheduler::instance().addWorker();
+				BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
+				TaskScheduler::instance().removeWorker();
+			}
+		}
+	}
+
+	void CoreApplication::preUpdate()
+	{
+		// Do nothing
+	}
+
+	void CoreApplication::postUpdate()
+	{
+		// Do nothing
+	}
+
+	void CoreApplication::stopMainLoop()
+	{
+		mRunMainLoop = false; // No sync primitives needed, in that rare case of 
+		// a race condition we might run the loop one extra iteration which is acceptable
+	}
+
+	void CoreApplication::quitRequested()
+	{
+		stopMainLoop();
+	}
+
+	void CoreApplication::setFPSLimit(UINT32 limit)
+	{
+		mFrameStep = (UINT64)1000000 / limit;
+	}
+
+	void CoreApplication::frameRenderingFinishedCallback()
+	{
+		BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
+
+		mIsFrameRenderingFinished = true;
+		BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
+	}
+
+	void CoreApplication::startUpRenderer()
+	{
+		RendererManager::instance().initialize();
+	}
+
+	void CoreApplication::beginCoreProfiling()
+	{
+		gProfilerCPU().beginThread("Core");
+		ProfilerGPU::instance().beginFrame();
+	}
+
+	void CoreApplication::endCoreProfiling()
+	{
+		ProfilerGPU::instance().endFrame();
+		ProfilerGPU::instance()._update();
+
+		gProfilerCPU().endThread();
+		gProfiler()._updateCore();
+	}
+
+	void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
+	{
+		DynLib* loadedLibrary = gDynLibManager().load(pluginName);
+		if(library != nullptr)
+			*library = loadedLibrary;
+
+		void* retVal = nullptr;
+		if(loadedLibrary != nullptr)
+		{
+			if (passThrough == nullptr)
+			{
+				typedef void* (*LoadPluginFunc)();
+
+				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
+
+				if (loadPluginFunc != nullptr)
+					retVal = loadPluginFunc();
+			}
+			else
+			{
+				typedef void* (*LoadPluginFunc)(void*);
+
+				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
+
+				if (loadPluginFunc != nullptr)
+					retVal = loadPluginFunc(passThrough);
+			}
+
+			UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
+
+			if (loadPluginFunc != nullptr)
+				mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
+		}
+
+		return retVal;
+	}
+
+	void CoreApplication::unloadPlugin(DynLib* library)
+	{
+		typedef void (*UnloadPluginFunc)();
+
+		UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
+
+		if(unloadPluginFunc != nullptr)
+			unloadPluginFunc();
+
+		mPluginUpdateFunctions.erase(library);
+		gDynLibManager().unload(library);
+	}
+
+	ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
+	{
+		return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
+	}
+
+	CoreApplication& gCoreApplication()
+	{
+		return CoreApplication::instance();
+	}
 }

+ 188 - 188
Source/BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -1,189 +1,189 @@
-#include "BsFPhysXCollider.h"
-#include "BsPhysX.h"
-#include "BsPhysXRigidbody.h"
-#include "BsPhysXMaterial.h"
-#include "PxScene.h"
-#include "PxShape.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	FPhysXCollider::FPhysXCollider(PxShape* shape)
-		:mShape(shape)
-	{
-		mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
-		mStaticBody->attachShape(*mShape);
-
-		PxScene* scene = gPhysX().getScene();
-		scene->addActor(*mStaticBody);
-
-		updateFilter();
-	}
-
-	FPhysXCollider::~FPhysXCollider()
-	{
-		if (mStaticBody != nullptr)
-			mStaticBody->release();
-
-		mShape->release();
-	}
-
-	Vector3 FPhysXCollider::getPosition() const
-	{
-		return fromPxVector(mShape->getLocalPose().p);
-	}
-
-	Quaternion FPhysXCollider::getRotation() const
-	{
-		return fromPxQuaternion(mShape->getLocalPose().q);
-	}
-
-	void FPhysXCollider::setTransform(const Vector3& pos, const Quaternion& rotation)
-	{
-		mShape->setLocalPose(toPxTransform(pos, rotation));
-	}
-
-	void FPhysXCollider::setIsTrigger(bool value)
-	{
-		if(value)
-		{
-			mShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
-			mShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true);
-
-			mIsTrigger = true;
-		}
-		else
-		{
-			mShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, false);
-			mShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true);
-
-			mIsTrigger = false;
-		}		
-	}
-
-	bool FPhysXCollider::getIsTrigger() const
-	{
-		return (UINT32)(mShape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) != 0;
-	}
-
-	void FPhysXCollider::setIsStatic(bool value)
-	{
-		if (mIsStatic == value)
-			return;
-
-		if (mStaticBody != nullptr)
-		{
-			mStaticBody->detachShape(*mShape);
-
-			mStaticBody->release();
-			mStaticBody = nullptr;
-		}
-
-		mIsStatic = value;
-
-		if (mIsStatic)
-		{
-			mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
-			mStaticBody->attachShape(*mShape);
-
-			PxScene* scene = gPhysX().getScene();
-			scene->addActor(*mStaticBody);
-		}
-	}
-
-	bool FPhysXCollider::getIsStatic() const
-	{
-		return mIsStatic;
-	}
-
-	void FPhysXCollider::setContactOffset(float value)
-	{
-		mShape->setContactOffset(value);
-	}
-
-	float FPhysXCollider::getContactOffset() const
-	{
-		return mShape->getContactOffset();
-	}
-
-	void FPhysXCollider::setRestOffset(float value)
-	{
-		mShape->setRestOffset(value);
-	}
-
-	float FPhysXCollider::getRestOffset() const
-	{
-		return mShape->getRestOffset();
-	}
-
-	void FPhysXCollider::setMaterial(const HPhysicsMaterial& material)
-	{
-		FCollider::setMaterial(material);
-
-		PhysXMaterial* physXmaterial = nullptr;
-		if(material.isLoaded())
-			physXmaterial = static_cast<PhysXMaterial*>(material.get());
-
-		PxMaterial* materials[1];
-		if (physXmaterial != nullptr)
-			materials[0] = physXmaterial->_getInternal();
-		else
-			materials[0] = nullptr;
-
-		mShape->setMaterials(materials, sizeof(materials));
-	}
-
-	UINT64 FPhysXCollider::getLayer() const
-	{
-		return mLayer;
-	}
-
-	void FPhysXCollider::setLayer(UINT64 layer)
-	{
-		mLayer = layer;
-		updateFilter();
-	}
-
-	CollisionReportMode FPhysXCollider::getCollisionReportMode() const
-	{
-		return mCollisionReportMode;
-	}
-
-	void FPhysXCollider::setCollisionReportMode(CollisionReportMode mode)
-	{
-		mCollisionReportMode = mode;
-		updateFilter();
-	}
-
-	void FPhysXCollider::_setCCD(bool enabled)
-	{
-		mCCD = enabled;
-		updateFilter();
-	}
-
-	void FPhysXCollider::updateFilter()
-	{
-		PxFilterData data;
-		memcpy(&data.word0, &mLayer, sizeof(mLayer));
-		mShape->setSimulationFilterData(data);
-		mShape->setQueryFilterData(data);
-
-		PhysXObjectFilterFlags flags;
-
-		switch(mCollisionReportMode)
-		{
-		case CollisionReportMode::None:
-			flags |= PhysXObjectFilterFlag::NoReport;
-		case CollisionReportMode::Report:
-			flags |= PhysXObjectFilterFlag::ReportBasic;
-		case CollisionReportMode::ReportPersistent:
-			flags |= PhysXObjectFilterFlag::ReportAll;
-		}
-
-		if (mCCD)
-			flags |= PhysXObjectFilterFlag::CCD;
-
-		data.word2 = flags;
-	}
+#include "BsFPhysXCollider.h"
+#include "BsPhysX.h"
+#include "BsPhysXRigidbody.h"
+#include "BsPhysXMaterial.h"
+#include "PxScene.h"
+#include "PxShape.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	FPhysXCollider::FPhysXCollider(PxShape* shape)
+		:mShape(shape)
+	{
+		mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform(PxIdentity));
+		mStaticBody->attachShape(*mShape);
+
+		PxScene* scene = gPhysX().getScene();
+		scene->addActor(*mStaticBody);
+
+		updateFilter();
+	}
+
+	FPhysXCollider::~FPhysXCollider()
+	{
+		if (mStaticBody != nullptr)
+			mStaticBody->release();
+
+		mShape->release();
+	}
+
+	Vector3 FPhysXCollider::getPosition() const
+	{
+		return fromPxVector(mShape->getLocalPose().p);
+	}
+
+	Quaternion FPhysXCollider::getRotation() const
+	{
+		return fromPxQuaternion(mShape->getLocalPose().q);
+	}
+
+	void FPhysXCollider::setTransform(const Vector3& pos, const Quaternion& rotation)
+	{
+		mShape->setLocalPose(toPxTransform(pos, rotation));
+	}
+
+	void FPhysXCollider::setIsTrigger(bool value)
+	{
+		if(value)
+		{
+			mShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
+			mShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true);
+
+			mIsTrigger = true;
+		}
+		else
+		{
+			mShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, false);
+			mShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true);
+
+			mIsTrigger = false;
+		}		
+	}
+
+	bool FPhysXCollider::getIsTrigger() const
+	{
+		return (UINT32)(mShape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) != 0;
+	}
+
+	void FPhysXCollider::setIsStatic(bool value)
+	{
+		if (mIsStatic == value)
+			return;
+
+		if (mStaticBody != nullptr)
+		{
+			mStaticBody->detachShape(*mShape);
+
+			mStaticBody->release();
+			mStaticBody = nullptr;
+		}
+
+		mIsStatic = value;
+
+		if (mIsStatic)
+		{
+			mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform(PxIdentity));
+			mStaticBody->attachShape(*mShape);
+
+			PxScene* scene = gPhysX().getScene();
+			scene->addActor(*mStaticBody);
+		}
+	}
+
+	bool FPhysXCollider::getIsStatic() const
+	{
+		return mIsStatic;
+	}
+
+	void FPhysXCollider::setContactOffset(float value)
+	{
+		mShape->setContactOffset(value);
+	}
+
+	float FPhysXCollider::getContactOffset() const
+	{
+		return mShape->getContactOffset();
+	}
+
+	void FPhysXCollider::setRestOffset(float value)
+	{
+		mShape->setRestOffset(value);
+	}
+
+	float FPhysXCollider::getRestOffset() const
+	{
+		return mShape->getRestOffset();
+	}
+
+	void FPhysXCollider::setMaterial(const HPhysicsMaterial& material)
+	{
+		FCollider::setMaterial(material);
+
+		PhysXMaterial* physXmaterial = nullptr;
+		if(material.isLoaded())
+			physXmaterial = static_cast<PhysXMaterial*>(material.get());
+
+		PxMaterial* materials[1];
+		if (physXmaterial != nullptr)
+			materials[0] = physXmaterial->_getInternal();
+		else
+			materials[0] = gPhysX().getDefaultMaterial();
+
+		mShape->setMaterials(materials, sizeof(materials));
+	}
+
+	UINT64 FPhysXCollider::getLayer() const
+	{
+		return mLayer;
+	}
+
+	void FPhysXCollider::setLayer(UINT64 layer)
+	{
+		mLayer = layer;
+		updateFilter();
+	}
+
+	CollisionReportMode FPhysXCollider::getCollisionReportMode() const
+	{
+		return mCollisionReportMode;
+	}
+
+	void FPhysXCollider::setCollisionReportMode(CollisionReportMode mode)
+	{
+		mCollisionReportMode = mode;
+		updateFilter();
+	}
+
+	void FPhysXCollider::_setCCD(bool enabled)
+	{
+		mCCD = enabled;
+		updateFilter();
+	}
+
+	void FPhysXCollider::updateFilter()
+	{
+		PxFilterData data;
+		memcpy(&data.word0, &mLayer, sizeof(mLayer));
+		mShape->setSimulationFilterData(data);
+		mShape->setQueryFilterData(data);
+
+		PhysXObjectFilterFlags flags;
+
+		switch(mCollisionReportMode)
+		{
+		case CollisionReportMode::None:
+			flags |= PhysXObjectFilterFlag::NoReport;
+		case CollisionReportMode::Report:
+			flags |= PhysXObjectFilterFlag::ReportBasic;
+		case CollisionReportMode::ReportPersistent:
+			flags |= PhysXObjectFilterFlag::ReportAll;
+		}
+
+		if (mCCD)
+			flags |= PhysXObjectFilterFlag::CCD;
+
+		data.word2 = flags;
+	}
 }

+ 282 - 282
Source/BansheePhysX/Source/BsPhysXD6Joint.cpp

@@ -1,283 +1,283 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXD6Joint.h"
-#include "BsFPhysxJoint.h"
-#include "BsPhysX.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxD6Axis::Enum toPxAxis(PhysXD6Joint::Axis axis)
-	{
-		switch(axis)
-		{
-		default:
-		case PhysXD6Joint::Axis::X:
-			return PxD6Axis::eX;
-		case PhysXD6Joint::Axis::Y:
-			return PxD6Axis::eY;
-		case PhysXD6Joint::Axis::Z:
-			return PxD6Axis::eZ;
-		case PhysXD6Joint::Axis::Twist:
-			return PxD6Axis::eTWIST;
-		case PhysXD6Joint::Axis::SwingY:
-			return PxD6Axis::eSWING1;
-		case PhysXD6Joint::Axis::SwingZ:
-			return PxD6Axis::eSWING2;
-		}
-	}
-
-	PxD6Motion::Enum toPxMotion(PhysXD6Joint::Motion motion)
-	{
-		switch(motion)
-		{
-		default:
-		case PhysXD6Joint::Motion::Free:
-			return PxD6Motion::eFREE;
-		case PhysXD6Joint::Motion::Limited:
-			return PxD6Motion::eLIMITED;
-		case PhysXD6Joint::Motion::Locked:
-			return PxD6Motion::eLOCKED;
-		}
-	}
-
-	PxD6Drive::Enum toPxDrive(PhysXD6Joint::DriveType drive)
-	{
-		switch(drive)
-		{
-		default:
-		case PhysXD6Joint::DriveType::X:
-			return PxD6Drive::eX;
-		case PhysXD6Joint::DriveType::Y:
-			return PxD6Drive::eY;
-		case PhysXD6Joint::DriveType::Z:
-			return PxD6Drive::eZ;
-		case PhysXD6Joint::DriveType::Swing:
-			return PxD6Drive::eSWING;
-		case PhysXD6Joint::DriveType::Twist:
-			return PxD6Drive::eTWIST;
-		case PhysXD6Joint::DriveType::SLERP:
-			return PxD6Drive::eSLERP;
-		}
-	}
-
-	PhysXD6Joint::Motion fromPxMotion(PxD6Motion::Enum motion)
-	{
-		switch (motion)
-		{
-		default:
-		case PxD6Motion::eFREE:
-			return PhysXD6Joint::Motion::Free;
-		case PxD6Motion::eLIMITED:
-			return PhysXD6Joint::Motion::Limited;
-		case PxD6Motion::eLOCKED:
-			return PhysXD6Joint::Motion::Locked;
-		}
-	}
-
-
-	PhysXD6Joint::DriveType fromPxDrive(PxD6Drive::Enum drive)
-	{
-		switch (drive)
-		{
-		default:
-		case PxD6Drive::eX:
-			return PhysXD6Joint::DriveType::X;
-		case PxD6Drive::eY:
-			return PhysXD6Joint::DriveType::Y;
-		case PxD6Drive::eZ:
-			return PhysXD6Joint::DriveType::Z;
-		case PxD6Drive::eSWING:
-			return PhysXD6Joint::DriveType::Swing;
-		case PxD6Drive::eTWIST:
-			return PhysXD6Joint::DriveType::Twist;
-		case PxD6Drive::eSLERP:
-			return PhysXD6Joint::DriveType::SLERP;
-		}
-	}
-
-	PhysXD6Joint::PhysXD6Joint(PxPhysics* physx)
-	{
-		PxD6Joint* joint = PxD6JointCreate(*physx, nullptr, PxTransform(), nullptr, PxTransform());
-		joint->userData = this;
-
-		mInternal = bs_new<FPhysXJoint>(joint);
-	}
-
-	PhysXD6Joint::~PhysXD6Joint()
-	{
-		bs_delete(mInternal);
-	}
-
-	PhysXD6Joint::Motion PhysXD6Joint::getMotion(Axis axis) const
-	{
-		return fromPxMotion(getInternal()->getMotion(toPxAxis(axis)));
-	}
-
-	void PhysXD6Joint::setMotion(Axis axis, Motion motion)
-	{
-		getInternal()->setMotion(toPxAxis(axis), toPxMotion(motion));
-	}
-
-	Radian PhysXD6Joint::getTwist() const
-	{
-		return Radian(getInternal()->getTwist());
-	}
-
-	Radian PhysXD6Joint::getSwingY() const
-	{
-		return Radian(getInternal()->getSwingYAngle());
-	}
-
-	Radian PhysXD6Joint::getSwingZ() const
-	{
-		return Radian(getInternal()->getSwingZAngle());
-	}
-
-	LimitLinear PhysXD6Joint::getLimitLinear() const
-	{
-		PxJointLinearLimit pxLimit = getInternal()->getLinearLimit();
-
-		LimitLinear limit;
-		limit.extent = pxLimit.value;
-		limit.contactDist = pxLimit.contactDistance;
-		limit.restitution = pxLimit.restitution;
-		limit.spring.stiffness = pxLimit.stiffness;
-		limit.spring.damping = pxLimit.damping;
-
-		return limit;
-	}
-
-	void PhysXD6Joint::setLimitLinear(const LimitLinear& limit)
-	{
-		PxJointLinearLimit pxLimit(gPhysX().getScale(), limit.extent, limit.contactDist);
-		pxLimit.stiffness = limit.spring.stiffness;
-		pxLimit.damping = limit.spring.damping;
-		pxLimit.restitution = limit.restitution;
-
-		getInternal()->setLinearLimit(pxLimit);
-	}
-
-	LimitAngularRange PhysXD6Joint::getLimitTwist() const
-	{
-		PxJointAngularLimitPair pxLimit = getInternal()->getTwistLimit();
-
-		LimitAngularRange limit;
-		limit.lower = pxLimit.lower;
-		limit.upper = pxLimit.upper;
-		limit.contactDist = pxLimit.contactDistance;
-		limit.restitution = pxLimit.restitution;
-		limit.spring.stiffness = pxLimit.stiffness;
-		limit.spring.damping = pxLimit.damping;
-
-		return limit;
-	}
-
-	void PhysXD6Joint::setLimitTwist(const LimitAngularRange& limit)
-	{
-		PxJointAngularLimitPair pxLimit(limit.lower.valueRadians(), limit.upper.valueRadians(), limit.contactDist);
-		pxLimit.stiffness = limit.spring.stiffness;
-		pxLimit.damping = limit.spring.damping;
-		pxLimit.restitution = limit.restitution;
-
-		getInternal()->setTwistLimit(pxLimit);
-	}
-
-	LimitConeRange PhysXD6Joint::getLimitSwing() const
-	{
-		PxJointLimitCone pxLimit = getInternal()->getSwingLimit();
-
-		LimitConeRange limit;
-		limit.yLimitAngle = pxLimit.yAngle;
-		limit.zLimitAngle = pxLimit.zAngle;
-		limit.contactDist = pxLimit.contactDistance;
-		limit.restitution = pxLimit.restitution;
-		limit.spring.stiffness = pxLimit.stiffness;
-		limit.spring.damping = pxLimit.damping;
-
-		return limit;
-	}
-
-	void PhysXD6Joint::setLimitSwing(const LimitConeRange& limit)
-	{
-		PxJointLimitCone pxLimit(limit.yLimitAngle.valueRadians(), limit.zLimitAngle.valueRadians(), limit.contactDist);
-		pxLimit.stiffness = limit.spring.stiffness;
-		pxLimit.damping = limit.spring.damping;
-		pxLimit.restitution = limit.restitution;
-
-		getInternal()->setSwingLimit(pxLimit);
-	}
-
-	PhysXD6Joint::Drive PhysXD6Joint::getDrive(DriveType type) const
-	{
-		PxD6JointDrive pxDrive = getInternal()->getDrive(toPxDrive(type));
-
-		Drive drive;
-		drive.acceleration = pxDrive.flags & PxD6JointDriveFlag::eACCELERATION;
-		drive.stiffness = pxDrive.stiffness;
-		drive.damping = pxDrive.damping;
-		drive.forceLimit = pxDrive.forceLimit;
-
-		return drive;
-	}
-
-	void PhysXD6Joint::setDrive(DriveType type, const Drive& drive)
-	{
-		PxD6JointDrive pxDrive;
-
-		if(drive.acceleration)
-			pxDrive.flags = PxD6JointDriveFlag::eACCELERATION;
-
-		pxDrive.stiffness = drive.stiffness;
-		pxDrive.damping = drive.damping;
-		pxDrive.forceLimit = drive.forceLimit;
-
-		getInternal()->setDrive(toPxDrive(type), pxDrive);
-	}
-
-	Vector3 PhysXD6Joint::getDrivePosition() const
-	{
-		return fromPxVector(getInternal()->getDrivePosition().p);
-	}
-
-	Quaternion PhysXD6Joint::getDriveRotation() const
-	{
-		return fromPxQuaternion(getInternal()->getDrivePosition().q);
-	}
-
-	void PhysXD6Joint::setDriveTransform(const Vector3& position, const Quaternion& rotation)
-	{
-		getInternal()->setDrivePosition(toPxTransform(position, rotation));
-	}
-
-	Vector3 PhysXD6Joint::getDriveLinearVelocity() const
-	{
-		PxVec3 linear;
-		PxVec3 angular;
-
-		getInternal()->getDriveVelocity(linear, angular);
-		return fromPxVector(linear);
-	}
-
-	Vector3 PhysXD6Joint::getDriveAngularVelocity() const
-	{
-		PxVec3 linear;
-		PxVec3 angular;
-
-		getInternal()->getDriveVelocity(linear, angular);
-		return fromPxVector(angular);
-	}
-
-	void PhysXD6Joint::setDriveVelocity(const Vector3& linear, const Vector3& angular)
-	{
-		getInternal()->setDriveVelocity(toPxVector(linear), toPxVector(angular));
-	}
-
-	PxD6Joint* PhysXD6Joint::getInternal() const
-	{
-		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
-
-		return static_cast<PxD6Joint*>(internal->_getInternal());
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXD6Joint.h"
+#include "BsFPhysxJoint.h"
+#include "BsPhysX.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxD6Axis::Enum toPxAxis(PhysXD6Joint::Axis axis)
+	{
+		switch(axis)
+		{
+		default:
+		case PhysXD6Joint::Axis::X:
+			return PxD6Axis::eX;
+		case PhysXD6Joint::Axis::Y:
+			return PxD6Axis::eY;
+		case PhysXD6Joint::Axis::Z:
+			return PxD6Axis::eZ;
+		case PhysXD6Joint::Axis::Twist:
+			return PxD6Axis::eTWIST;
+		case PhysXD6Joint::Axis::SwingY:
+			return PxD6Axis::eSWING1;
+		case PhysXD6Joint::Axis::SwingZ:
+			return PxD6Axis::eSWING2;
+		}
+	}
+
+	PxD6Motion::Enum toPxMotion(PhysXD6Joint::Motion motion)
+	{
+		switch(motion)
+		{
+		default:
+		case PhysXD6Joint::Motion::Free:
+			return PxD6Motion::eFREE;
+		case PhysXD6Joint::Motion::Limited:
+			return PxD6Motion::eLIMITED;
+		case PhysXD6Joint::Motion::Locked:
+			return PxD6Motion::eLOCKED;
+		}
+	}
+
+	PxD6Drive::Enum toPxDrive(PhysXD6Joint::DriveType drive)
+	{
+		switch(drive)
+		{
+		default:
+		case PhysXD6Joint::DriveType::X:
+			return PxD6Drive::eX;
+		case PhysXD6Joint::DriveType::Y:
+			return PxD6Drive::eY;
+		case PhysXD6Joint::DriveType::Z:
+			return PxD6Drive::eZ;
+		case PhysXD6Joint::DriveType::Swing:
+			return PxD6Drive::eSWING;
+		case PhysXD6Joint::DriveType::Twist:
+			return PxD6Drive::eTWIST;
+		case PhysXD6Joint::DriveType::SLERP:
+			return PxD6Drive::eSLERP;
+		}
+	}
+
+	PhysXD6Joint::Motion fromPxMotion(PxD6Motion::Enum motion)
+	{
+		switch (motion)
+		{
+		default:
+		case PxD6Motion::eFREE:
+			return PhysXD6Joint::Motion::Free;
+		case PxD6Motion::eLIMITED:
+			return PhysXD6Joint::Motion::Limited;
+		case PxD6Motion::eLOCKED:
+			return PhysXD6Joint::Motion::Locked;
+		}
+	}
+
+
+	PhysXD6Joint::DriveType fromPxDrive(PxD6Drive::Enum drive)
+	{
+		switch (drive)
+		{
+		default:
+		case PxD6Drive::eX:
+			return PhysXD6Joint::DriveType::X;
+		case PxD6Drive::eY:
+			return PhysXD6Joint::DriveType::Y;
+		case PxD6Drive::eZ:
+			return PhysXD6Joint::DriveType::Z;
+		case PxD6Drive::eSWING:
+			return PhysXD6Joint::DriveType::Swing;
+		case PxD6Drive::eTWIST:
+			return PhysXD6Joint::DriveType::Twist;
+		case PxD6Drive::eSLERP:
+			return PhysXD6Joint::DriveType::SLERP;
+		}
+	}
+
+	PhysXD6Joint::PhysXD6Joint(PxPhysics* physx)
+	{
+		PxD6Joint* joint = PxD6JointCreate(*physx, nullptr, PxTransform(PxIdentity), nullptr, PxTransform(PxIdentity));
+		joint->userData = this;
+
+		mInternal = bs_new<FPhysXJoint>(joint);
+	}
+
+	PhysXD6Joint::~PhysXD6Joint()
+	{
+		bs_delete(mInternal);
+	}
+
+	PhysXD6Joint::Motion PhysXD6Joint::getMotion(Axis axis) const
+	{
+		return fromPxMotion(getInternal()->getMotion(toPxAxis(axis)));
+	}
+
+	void PhysXD6Joint::setMotion(Axis axis, Motion motion)
+	{
+		getInternal()->setMotion(toPxAxis(axis), toPxMotion(motion));
+	}
+
+	Radian PhysXD6Joint::getTwist() const
+	{
+		return Radian(getInternal()->getTwist());
+	}
+
+	Radian PhysXD6Joint::getSwingY() const
+	{
+		return Radian(getInternal()->getSwingYAngle());
+	}
+
+	Radian PhysXD6Joint::getSwingZ() const
+	{
+		return Radian(getInternal()->getSwingZAngle());
+	}
+
+	LimitLinear PhysXD6Joint::getLimitLinear() const
+	{
+		PxJointLinearLimit pxLimit = getInternal()->getLinearLimit();
+
+		LimitLinear limit;
+		limit.extent = pxLimit.value;
+		limit.contactDist = pxLimit.contactDistance;
+		limit.restitution = pxLimit.restitution;
+		limit.spring.stiffness = pxLimit.stiffness;
+		limit.spring.damping = pxLimit.damping;
+
+		return limit;
+	}
+
+	void PhysXD6Joint::setLimitLinear(const LimitLinear& limit)
+	{
+		PxJointLinearLimit pxLimit(gPhysX().getScale(), limit.extent, limit.contactDist);
+		pxLimit.stiffness = limit.spring.stiffness;
+		pxLimit.damping = limit.spring.damping;
+		pxLimit.restitution = limit.restitution;
+
+		getInternal()->setLinearLimit(pxLimit);
+	}
+
+	LimitAngularRange PhysXD6Joint::getLimitTwist() const
+	{
+		PxJointAngularLimitPair pxLimit = getInternal()->getTwistLimit();
+
+		LimitAngularRange limit;
+		limit.lower = pxLimit.lower;
+		limit.upper = pxLimit.upper;
+		limit.contactDist = pxLimit.contactDistance;
+		limit.restitution = pxLimit.restitution;
+		limit.spring.stiffness = pxLimit.stiffness;
+		limit.spring.damping = pxLimit.damping;
+
+		return limit;
+	}
+
+	void PhysXD6Joint::setLimitTwist(const LimitAngularRange& limit)
+	{
+		PxJointAngularLimitPair pxLimit(limit.lower.valueRadians(), limit.upper.valueRadians(), limit.contactDist);
+		pxLimit.stiffness = limit.spring.stiffness;
+		pxLimit.damping = limit.spring.damping;
+		pxLimit.restitution = limit.restitution;
+
+		getInternal()->setTwistLimit(pxLimit);
+	}
+
+	LimitConeRange PhysXD6Joint::getLimitSwing() const
+	{
+		PxJointLimitCone pxLimit = getInternal()->getSwingLimit();
+
+		LimitConeRange limit;
+		limit.yLimitAngle = pxLimit.yAngle;
+		limit.zLimitAngle = pxLimit.zAngle;
+		limit.contactDist = pxLimit.contactDistance;
+		limit.restitution = pxLimit.restitution;
+		limit.spring.stiffness = pxLimit.stiffness;
+		limit.spring.damping = pxLimit.damping;
+
+		return limit;
+	}
+
+	void PhysXD6Joint::setLimitSwing(const LimitConeRange& limit)
+	{
+		PxJointLimitCone pxLimit(limit.yLimitAngle.valueRadians(), limit.zLimitAngle.valueRadians(), limit.contactDist);
+		pxLimit.stiffness = limit.spring.stiffness;
+		pxLimit.damping = limit.spring.damping;
+		pxLimit.restitution = limit.restitution;
+
+		getInternal()->setSwingLimit(pxLimit);
+	}
+
+	PhysXD6Joint::Drive PhysXD6Joint::getDrive(DriveType type) const
+	{
+		PxD6JointDrive pxDrive = getInternal()->getDrive(toPxDrive(type));
+
+		Drive drive;
+		drive.acceleration = pxDrive.flags & PxD6JointDriveFlag::eACCELERATION;
+		drive.stiffness = pxDrive.stiffness;
+		drive.damping = pxDrive.damping;
+		drive.forceLimit = pxDrive.forceLimit;
+
+		return drive;
+	}
+
+	void PhysXD6Joint::setDrive(DriveType type, const Drive& drive)
+	{
+		PxD6JointDrive pxDrive;
+
+		if(drive.acceleration)
+			pxDrive.flags = PxD6JointDriveFlag::eACCELERATION;
+
+		pxDrive.stiffness = drive.stiffness;
+		pxDrive.damping = drive.damping;
+		pxDrive.forceLimit = drive.forceLimit;
+
+		getInternal()->setDrive(toPxDrive(type), pxDrive);
+	}
+
+	Vector3 PhysXD6Joint::getDrivePosition() const
+	{
+		return fromPxVector(getInternal()->getDrivePosition().p);
+	}
+
+	Quaternion PhysXD6Joint::getDriveRotation() const
+	{
+		return fromPxQuaternion(getInternal()->getDrivePosition().q);
+	}
+
+	void PhysXD6Joint::setDriveTransform(const Vector3& position, const Quaternion& rotation)
+	{
+		getInternal()->setDrivePosition(toPxTransform(position, rotation));
+	}
+
+	Vector3 PhysXD6Joint::getDriveLinearVelocity() const
+	{
+		PxVec3 linear;
+		PxVec3 angular;
+
+		getInternal()->getDriveVelocity(linear, angular);
+		return fromPxVector(linear);
+	}
+
+	Vector3 PhysXD6Joint::getDriveAngularVelocity() const
+	{
+		PxVec3 linear;
+		PxVec3 angular;
+
+		getInternal()->getDriveVelocity(linear, angular);
+		return fromPxVector(angular);
+	}
+
+	void PhysXD6Joint::setDriveVelocity(const Vector3& linear, const Vector3& angular)
+	{
+		getInternal()->setDriveVelocity(toPxVector(linear), toPxVector(angular));
+	}
+
+	PxD6Joint* PhysXD6Joint::getInternal() const
+	{
+		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
+
+		return static_cast<PxD6Joint*>(internal->_getInternal());
+	}
 }

+ 101 - 101
Source/BansheePhysX/Source/BsPhysXDistanceJoint.cpp

@@ -1,102 +1,102 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXDistanceJoint.h"
-#include "BsFPhysxJoint.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxDistanceJointFlag::Enum toPxFlag(PhysXDistanceJoint::Flag flag)
-	{
-		switch (flag)
-		{
-		case PhysXDistanceJoint::Flag::MaxDistance:
-			return PxDistanceJointFlag::eMAX_DISTANCE_ENABLED;
-		case PhysXDistanceJoint::Flag::MinDistance:
-			return PxDistanceJointFlag::eMIN_DISTANCE_ENABLED;
-		default:
-		case PhysXDistanceJoint::Flag::Spring:
-			return PxDistanceJointFlag::eSPRING_ENABLED;
-		}
-	}
-
-	PhysXDistanceJoint::PhysXDistanceJoint(PxPhysics* physx)
-	{
-		PxDistanceJoint* joint = PxDistanceJointCreate(*physx, nullptr, PxTransform(), nullptr, PxTransform());
-		joint->userData = this;
-
-		mInternal = bs_new<FPhysXJoint>(joint);
-	}
-
-	PhysXDistanceJoint::~PhysXDistanceJoint()
-	{
-		bs_delete(mInternal);
-	}
-
-	float PhysXDistanceJoint::getDistance() const
-	{
-		return getInternal()->getDistance();
-	}
-
-	float PhysXDistanceJoint::getMinDistance() const
-	{
-		return getInternal()->getMinDistance();
-	}
-
-	void PhysXDistanceJoint::setMinDistance(float value)
-	{
-		getInternal()->setMinDistance(value);
-	}
-
-	float PhysXDistanceJoint::getMaxDistance() const
-	{
-		return getInternal()->getMaxDistance();
-	}
-
-	void PhysXDistanceJoint::setMaxDistance(float value)
-	{
-		getInternal()->setMaxDistance(value);
-	}
-
-	float PhysXDistanceJoint::getTolerance() const
-	{
-		return getInternal()->getTolerance();
-	}
-
-	void PhysXDistanceJoint::setTolerance(float value)
-	{
-		getInternal()->setTolerance(value);
-	}
-
-	Spring PhysXDistanceJoint::getSpring() const
-	{
-		float damping = getInternal()->getDamping();
-		float stiffness = getInternal()->getStiffness();
-
-		return Spring(stiffness, damping);
-	}
-
-	void PhysXDistanceJoint::setSpring(const Spring& value)
-	{
-		getInternal()->setDamping(value.damping);
-		getInternal()->setStiffness(value.stiffness);
-	}
-
-	void PhysXDistanceJoint::setFlag(Flag flag, bool enabled)
-	{
-		getInternal()->setDistanceJointFlag(toPxFlag(flag), enabled);
-	}
-
-	bool PhysXDistanceJoint::hasFlag(Flag flag) const
-	{
-		return getInternal()->getDistanceJointFlags() & toPxFlag(flag);
-	}
-
-	PxDistanceJoint* PhysXDistanceJoint::getInternal() const
-	{
-		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
-
-		return static_cast<PxDistanceJoint*>(internal->_getInternal());
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXDistanceJoint.h"
+#include "BsFPhysxJoint.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxDistanceJointFlag::Enum toPxFlag(PhysXDistanceJoint::Flag flag)
+	{
+		switch (flag)
+		{
+		case PhysXDistanceJoint::Flag::MaxDistance:
+			return PxDistanceJointFlag::eMAX_DISTANCE_ENABLED;
+		case PhysXDistanceJoint::Flag::MinDistance:
+			return PxDistanceJointFlag::eMIN_DISTANCE_ENABLED;
+		default:
+		case PhysXDistanceJoint::Flag::Spring:
+			return PxDistanceJointFlag::eSPRING_ENABLED;
+		}
+	}
+
+	PhysXDistanceJoint::PhysXDistanceJoint(PxPhysics* physx)
+	{
+		PxDistanceJoint* joint = PxDistanceJointCreate(*physx, nullptr, PxTransform(PxIdentity), nullptr, PxTransform(PxIdentity));
+		joint->userData = this;
+
+		mInternal = bs_new<FPhysXJoint>(joint);
+	}
+
+	PhysXDistanceJoint::~PhysXDistanceJoint()
+	{
+		bs_delete(mInternal);
+	}
+
+	float PhysXDistanceJoint::getDistance() const
+	{
+		return getInternal()->getDistance();
+	}
+
+	float PhysXDistanceJoint::getMinDistance() const
+	{
+		return getInternal()->getMinDistance();
+	}
+
+	void PhysXDistanceJoint::setMinDistance(float value)
+	{
+		getInternal()->setMinDistance(value);
+	}
+
+	float PhysXDistanceJoint::getMaxDistance() const
+	{
+		return getInternal()->getMaxDistance();
+	}
+
+	void PhysXDistanceJoint::setMaxDistance(float value)
+	{
+		getInternal()->setMaxDistance(value);
+	}
+
+	float PhysXDistanceJoint::getTolerance() const
+	{
+		return getInternal()->getTolerance();
+	}
+
+	void PhysXDistanceJoint::setTolerance(float value)
+	{
+		getInternal()->setTolerance(value);
+	}
+
+	Spring PhysXDistanceJoint::getSpring() const
+	{
+		float damping = getInternal()->getDamping();
+		float stiffness = getInternal()->getStiffness();
+
+		return Spring(stiffness, damping);
+	}
+
+	void PhysXDistanceJoint::setSpring(const Spring& value)
+	{
+		getInternal()->setDamping(value.damping);
+		getInternal()->setStiffness(value.stiffness);
+	}
+
+	void PhysXDistanceJoint::setFlag(Flag flag, bool enabled)
+	{
+		getInternal()->setDistanceJointFlag(toPxFlag(flag), enabled);
+	}
+
+	bool PhysXDistanceJoint::hasFlag(Flag flag) const
+	{
+		return getInternal()->getDistanceJointFlags() & toPxFlag(flag);
+	}
+
+	PxDistanceJoint* PhysXDistanceJoint::getInternal() const
+	{
+		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
+
+		return static_cast<PxDistanceJoint*>(internal->_getInternal());
+	}
 }

+ 22 - 22
Source/BansheePhysX/Source/BsPhysXFixedJoint.cpp

@@ -1,23 +1,23 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXFixedJoint.h"
-#include "BsFPhysxJoint.h"
-#include "extensions\PxFixedJoint.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PhysXFixedJoint::PhysXFixedJoint(PxPhysics* physx)
-	{
-		PxFixedJoint* joint = PxFixedJointCreate(*physx, nullptr, PxTransform(), nullptr, PxTransform());
-		joint->userData = this;
-
-		mInternal = bs_new<FPhysXJoint>(joint);
-	}
-
-	PhysXFixedJoint::~PhysXFixedJoint()
-	{
-		bs_delete(mInternal);
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXFixedJoint.h"
+#include "BsFPhysxJoint.h"
+#include "extensions\PxFixedJoint.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PhysXFixedJoint::PhysXFixedJoint(PxPhysics* physx)
+	{
+		PxFixedJoint* joint = PxFixedJointCreate(*physx, nullptr, PxTransform(PxIdentity), nullptr, PxTransform(PxIdentity));
+		joint->userData = this;
+
+		mInternal = bs_new<FPhysXJoint>(joint);
+	}
+
+	PhysXFixedJoint::~PhysXFixedJoint()
+	{
+		bs_delete(mInternal);
+	}
 }

+ 104 - 104
Source/BansheePhysX/Source/BsPhysXHingeJoint.cpp

@@ -1,105 +1,105 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXHingeJoint.h"
-#include "BsFPhysxJoint.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxRevoluteJointFlag::Enum toPxFlag(PhysXHingeJoint::Flag flag)
-	{
-		switch (flag)
-		{
-		case PhysXHingeJoint::Flag::Limit:
-			return PxRevoluteJointFlag::eLIMIT_ENABLED;
-		default:
-		case PhysXHingeJoint::Flag::Drive:
-			return PxRevoluteJointFlag::eDRIVE_ENABLED;
-		}
-	}
-
-	PhysXHingeJoint::PhysXHingeJoint(PxPhysics* physx)
-	{
-		PxRevoluteJoint* joint = PxRevoluteJointCreate(*physx, nullptr, PxTransform(), nullptr, PxTransform());
-		joint->userData = this;
-
-		mInternal = bs_new<FPhysXJoint>(joint);
-	}
-
-	PhysXHingeJoint::~PhysXHingeJoint()
-	{
-		bs_delete(mInternal);
-	}
-
-	Radian PhysXHingeJoint::getAngle() const
-	{
-		return Radian(getInternal()->getAngle());
-	}
-
-	float PhysXHingeJoint::getSpeed() const
-	{
-		return getInternal()->getVelocity();
-	}
-
-	LimitAngularRange PhysXHingeJoint::getLimit() const
-	{
-		PxJointAngularLimitPair pxLimit = getInternal()->getLimit();
-
-		LimitAngularRange limit;
-		limit.lower = pxLimit.lower;
-		limit.upper = pxLimit.upper;
-		limit.contactDist = pxLimit.contactDistance;
-		limit.restitution = pxLimit.restitution;
-		limit.spring.stiffness = pxLimit.stiffness;
-		limit.spring.damping = pxLimit.damping;
-
-		return limit;
-	}
-
-	void PhysXHingeJoint::setLimit(const LimitAngularRange& limit)
-	{
-		PxJointAngularLimitPair pxLimit(limit.lower.valueRadians(), limit.upper.valueRadians(), limit.contactDist);
-		pxLimit.stiffness = limit.spring.stiffness;
-		pxLimit.damping = limit.spring.damping;
-		pxLimit.restitution = limit.restitution;
-
-		getInternal()->setLimit(pxLimit);
-	}
-
-	PhysXHingeJoint::Drive PhysXHingeJoint::getDrive() const
-	{
-		Drive drive;
-		drive.speed = getInternal()->getDriveVelocity();
-		drive.forceLimit = getInternal()->getDriveForceLimit();
-		drive.gearRatio = getInternal()->getDriveGearRatio();
-		drive.freeSpin = getInternal()->getRevoluteJointFlags() & PxRevoluteJointFlag::eDRIVE_FREESPIN;
-
-		return drive;
-	}
-
-	void PhysXHingeJoint::setDrive(const Drive& drive)
-	{
-		getInternal()->setDriveVelocity(drive.speed);
-		getInternal()->setDriveForceLimit(drive.forceLimit);
-		getInternal()->setDriveGearRatio(drive.gearRatio);
-		getInternal()->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, drive.freeSpin);
-	}
-
-	void PhysXHingeJoint::setFlag(Flag flag, bool enabled)
-	{
-		getInternal()->setRevoluteJointFlag(toPxFlag(flag), enabled);
-	}
-
-	bool PhysXHingeJoint::hasFlag(Flag flag) const
-	{
-		return getInternal()->getRevoluteJointFlags() & toPxFlag(flag);
-	}
-
-	PxRevoluteJoint* PhysXHingeJoint::getInternal() const
-	{
-		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
-
-		return static_cast<PxRevoluteJoint*>(internal->_getInternal());
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXHingeJoint.h"
+#include "BsFPhysxJoint.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxRevoluteJointFlag::Enum toPxFlag(PhysXHingeJoint::Flag flag)
+	{
+		switch (flag)
+		{
+		case PhysXHingeJoint::Flag::Limit:
+			return PxRevoluteJointFlag::eLIMIT_ENABLED;
+		default:
+		case PhysXHingeJoint::Flag::Drive:
+			return PxRevoluteJointFlag::eDRIVE_ENABLED;
+		}
+	}
+
+	PhysXHingeJoint::PhysXHingeJoint(PxPhysics* physx)
+	{
+		PxRevoluteJoint* joint = PxRevoluteJointCreate(*physx, nullptr, PxTransform(PxIdentity), nullptr, PxTransform(PxIdentity));
+		joint->userData = this;
+
+		mInternal = bs_new<FPhysXJoint>(joint);
+	}
+
+	PhysXHingeJoint::~PhysXHingeJoint()
+	{
+		bs_delete(mInternal);
+	}
+
+	Radian PhysXHingeJoint::getAngle() const
+	{
+		return Radian(getInternal()->getAngle());
+	}
+
+	float PhysXHingeJoint::getSpeed() const
+	{
+		return getInternal()->getVelocity();
+	}
+
+	LimitAngularRange PhysXHingeJoint::getLimit() const
+	{
+		PxJointAngularLimitPair pxLimit = getInternal()->getLimit();
+
+		LimitAngularRange limit;
+		limit.lower = pxLimit.lower;
+		limit.upper = pxLimit.upper;
+		limit.contactDist = pxLimit.contactDistance;
+		limit.restitution = pxLimit.restitution;
+		limit.spring.stiffness = pxLimit.stiffness;
+		limit.spring.damping = pxLimit.damping;
+
+		return limit;
+	}
+
+	void PhysXHingeJoint::setLimit(const LimitAngularRange& limit)
+	{
+		PxJointAngularLimitPair pxLimit(limit.lower.valueRadians(), limit.upper.valueRadians(), limit.contactDist);
+		pxLimit.stiffness = limit.spring.stiffness;
+		pxLimit.damping = limit.spring.damping;
+		pxLimit.restitution = limit.restitution;
+
+		getInternal()->setLimit(pxLimit);
+	}
+
+	PhysXHingeJoint::Drive PhysXHingeJoint::getDrive() const
+	{
+		Drive drive;
+		drive.speed = getInternal()->getDriveVelocity();
+		drive.forceLimit = getInternal()->getDriveForceLimit();
+		drive.gearRatio = getInternal()->getDriveGearRatio();
+		drive.freeSpin = getInternal()->getRevoluteJointFlags() & PxRevoluteJointFlag::eDRIVE_FREESPIN;
+
+		return drive;
+	}
+
+	void PhysXHingeJoint::setDrive(const Drive& drive)
+	{
+		getInternal()->setDriveVelocity(drive.speed);
+		getInternal()->setDriveForceLimit(drive.forceLimit);
+		getInternal()->setDriveGearRatio(drive.gearRatio);
+		getInternal()->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, drive.freeSpin);
+	}
+
+	void PhysXHingeJoint::setFlag(Flag flag, bool enabled)
+	{
+		getInternal()->setRevoluteJointFlag(toPxFlag(flag), enabled);
+	}
+
+	bool PhysXHingeJoint::hasFlag(Flag flag) const
+	{
+		return getInternal()->getRevoluteJointFlags() & toPxFlag(flag);
+	}
+
+	PxRevoluteJoint* PhysXHingeJoint::getInternal() const
+	{
+		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
+
+		return static_cast<PxRevoluteJoint*>(internal->_getInternal());
+	}
 }

+ 84 - 84
Source/BansheePhysX/Source/BsPhysXSliderJoint.cpp

@@ -1,85 +1,85 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXSliderJoint.h"
-#include "BsFPhysxJoint.h"
-#include "BsPhysX.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxPrismaticJointFlag::Enum toPxFlag(PhysXSliderJoint::Flag flag)
-	{
-		switch (flag)
-		{
-		default:
-		case PhysXSliderJoint::Flag::Limit:
-			return PxPrismaticJointFlag::eLIMIT_ENABLED;
-		}
-	}
-
-	PhysXSliderJoint::PhysXSliderJoint(PxPhysics* physx)
-	{
-		PxPrismaticJoint* joint = PxPrismaticJointCreate(*physx, nullptr, PxTransform(), nullptr, PxTransform());
-		joint->userData = this;
-
-		mInternal = bs_new<FPhysXJoint>(joint);
-	}
-
-	PhysXSliderJoint::~PhysXSliderJoint()
-	{
-		bs_delete(mInternal);
-	}
-
-	float PhysXSliderJoint::getPosition() const
-	{
-		return getInternal()->getPosition();
-	}
-
-	float PhysXSliderJoint::getSpeed() const
-	{
-		return getInternal()->getVelocity();
-	}
-
-	LimitLinearRange PhysXSliderJoint::getLimit() const
-	{
-		PxJointLinearLimitPair pxLimit = getInternal()->getLimit();
-
-		LimitLinearRange limit;
-		limit.lower = pxLimit.lower;
-		limit.upper = pxLimit.upper;
-		limit.contactDist = pxLimit.contactDistance;
-		limit.restitution = pxLimit.restitution;
-		limit.spring.stiffness = pxLimit.stiffness;
-		limit.spring.damping = pxLimit.damping;
-
-		return limit;
-	}
-
-	void PhysXSliderJoint::setLimit(const LimitLinearRange& limit)
-	{
-		PxJointLinearLimitPair pxLimit(gPhysX().getScale(), limit.lower, limit.upper, limit.contactDist);
-		pxLimit.stiffness = limit.spring.stiffness;
-		pxLimit.damping = limit.spring.damping;
-		pxLimit.restitution = limit.restitution;
-
-		getInternal()->setLimit(pxLimit);
-	}
-
-	void PhysXSliderJoint::setFlag(Flag flag, bool enabled)
-	{
-		getInternal()->setPrismaticJointFlag(toPxFlag(flag), enabled);
-	}
-
-	bool PhysXSliderJoint::hasFlag(Flag flag) const
-	{
-		return getInternal()->getPrismaticJointFlags() & toPxFlag(flag);
-	}
-
-	PxPrismaticJoint* PhysXSliderJoint::getInternal() const
-	{
-		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
-
-		return static_cast<PxPrismaticJoint*>(internal->_getInternal());
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXSliderJoint.h"
+#include "BsFPhysxJoint.h"
+#include "BsPhysX.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxPrismaticJointFlag::Enum toPxFlag(PhysXSliderJoint::Flag flag)
+	{
+		switch (flag)
+		{
+		default:
+		case PhysXSliderJoint::Flag::Limit:
+			return PxPrismaticJointFlag::eLIMIT_ENABLED;
+		}
+	}
+
+	PhysXSliderJoint::PhysXSliderJoint(PxPhysics* physx)
+	{
+		PxPrismaticJoint* joint = PxPrismaticJointCreate(*physx, nullptr, PxTransform(PxIdentity), nullptr, PxTransform(PxIdentity));
+		joint->userData = this;
+
+		mInternal = bs_new<FPhysXJoint>(joint);
+	}
+
+	PhysXSliderJoint::~PhysXSliderJoint()
+	{
+		bs_delete(mInternal);
+	}
+
+	float PhysXSliderJoint::getPosition() const
+	{
+		return getInternal()->getPosition();
+	}
+
+	float PhysXSliderJoint::getSpeed() const
+	{
+		return getInternal()->getVelocity();
+	}
+
+	LimitLinearRange PhysXSliderJoint::getLimit() const
+	{
+		PxJointLinearLimitPair pxLimit = getInternal()->getLimit();
+
+		LimitLinearRange limit;
+		limit.lower = pxLimit.lower;
+		limit.upper = pxLimit.upper;
+		limit.contactDist = pxLimit.contactDistance;
+		limit.restitution = pxLimit.restitution;
+		limit.spring.stiffness = pxLimit.stiffness;
+		limit.spring.damping = pxLimit.damping;
+
+		return limit;
+	}
+
+	void PhysXSliderJoint::setLimit(const LimitLinearRange& limit)
+	{
+		PxJointLinearLimitPair pxLimit(gPhysX().getScale(), limit.lower, limit.upper, limit.contactDist);
+		pxLimit.stiffness = limit.spring.stiffness;
+		pxLimit.damping = limit.spring.damping;
+		pxLimit.restitution = limit.restitution;
+
+		getInternal()->setLimit(pxLimit);
+	}
+
+	void PhysXSliderJoint::setFlag(Flag flag, bool enabled)
+	{
+		getInternal()->setPrismaticJointFlag(toPxFlag(flag), enabled);
+	}
+
+	bool PhysXSliderJoint::hasFlag(Flag flag) const
+	{
+		return getInternal()->getPrismaticJointFlags() & toPxFlag(flag);
+	}
+
+	PxPrismaticJoint* PhysXSliderJoint::getInternal() const
+	{
+		FPhysXJoint* internal = static_cast<FPhysXJoint*>(mInternal);
+
+		return static_cast<PxPrismaticJoint*>(internal->_getInternal());
+	}
 }

+ 292 - 285
Source/BansheeUtility/Source/BsFrameAlloc.cpp

@@ -1,286 +1,293 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsFrameAlloc.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	FrameAlloc::MemBlock::MemBlock(UINT32 size)
-		:mData(nullptr), mFreePtr(0), mSize(size)
-	{ }
-
-	FrameAlloc::MemBlock::~MemBlock()
-	{ }
-
-	UINT8* FrameAlloc::MemBlock::alloc(UINT32 amount)
-	{
-		UINT8* freePtr = &mData[mFreePtr];
-		mFreePtr += amount;
-
-		return freePtr;
-	}
-
-	void FrameAlloc::MemBlock::clear()
-	{
-		mFreePtr = 0;
-	}
-
-#if BS_DEBUG_MODE
-	FrameAlloc::FrameAlloc(UINT32 blockSize)
-		:mBlockSize(blockSize), mFreeBlock(nullptr), mNextBlockIdx(0), mTotalAllocBytes(0),
-		mLastFrame(nullptr), mOwnerThread(BS_THREAD_CURRENT_ID)
-	{
-		allocBlock(mBlockSize);
-	}
-#else
-	FrameAlloc::FrameAlloc(UINT32 blockSize)
-		:mTotalAllocBytes(0), mFreeBlock(nullptr), mBlockSize(blockSize),
-		mLastFrame(nullptr), mNextBlockIdx(0)
-	{
-		allocBlock(mBlockSize);
-	}
-#endif
-
-	FrameAlloc::~FrameAlloc()
-	{
-		for(auto& block : mBlocks)
-			deallocBlock(block);
-	}
-
-	UINT8* FrameAlloc::alloc(UINT32 amount)
-	{
-#if BS_DEBUG_MODE
-		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
-
-		amount += sizeof(UINT32);
-#endif
-
-		UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
-		if(amount > freeMem)
-			allocBlock(amount);
-
-		UINT8* data = mFreeBlock->alloc(amount);
-
-#if BS_DEBUG_MODE
-		mTotalAllocBytes += amount;
-
-		UINT32* storedSize = reinterpret_cast<UINT32*>(data);
-		*storedSize = amount;
-
-		return data + sizeof(UINT32);
-#else
-		return data;
-#endif
-	}
-
-	UINT8* FrameAlloc::allocAligned(UINT32 amount, UINT32 alignment)
-	{
-#if BS_DEBUG_MODE
-		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
-
-		amount += sizeof(UINT32);
-#endif
-
-		UINT32 alignOffset = alignment - mFreeBlock->mFreePtr & (alignment - 1);
-
-		UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
-		if ((amount + alignOffset) > freeMem)
-		{
-			// New blocks are allocated on a 16 byte boundary, ensure we enough space is allocated taking into account
-			// the requested alignment
-
-			if (alignment > 16)
-				alignOffset = alignment - 16;
-			else
-				alignOffset = 0;
-
-			allocBlock(amount + alignOffset);
-		}
-
-		amount += alignOffset;
-		UINT8* data = mFreeBlock->alloc(amount);
-
-#if BS_DEBUG_MODE
-		mTotalAllocBytes += amount;
-
-		UINT32* storedSize = reinterpret_cast<UINT32*>(data + alignOffset);
-		*storedSize = amount;
-
-		return data + sizeof(UINT32) + alignOffset;
-#else
-		return data + alignOffset;
-#endif
-	}
-
-	void FrameAlloc::dealloc(UINT8* data)
-	{
-		// Dealloc is only used for debug and can be removed if needed. All the actual deallocation
-		// happens in clear()
-			
-#if BS_DEBUG_MODE
-		data -= sizeof(UINT32);
-		UINT32* storedSize = reinterpret_cast<UINT32*>(data);
-		mTotalAllocBytes -= *storedSize;
-#endif
-	}
-
-	void FrameAlloc::markFrame()
-	{
-		void** framePtr = (void**)alloc(sizeof(void*));
-		*framePtr = mLastFrame;
-		mLastFrame = framePtr;
-	}
-
-	void FrameAlloc::clear()
-	{
-#if BS_DEBUG_MODE
-		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
-#endif
-
-		if(mLastFrame != nullptr)
-		{
-			assert(mBlocks.size() > 0 && mNextBlockIdx > 0);
-
-			dealloc((UINT8*)mLastFrame);
-
-			UINT8* framePtr = (UINT8*)mLastFrame;
-			mLastFrame = *(void**)mLastFrame;
-
-#if BS_DEBUG_MODE
-			framePtr -= sizeof(UINT32);
-#endif
-
-			UINT32 startBlockIdx = mNextBlockIdx - 1;
-			UINT32 numFreedBlocks = 0;
-			for (INT32 i = startBlockIdx; i >= 0; i--)
-			{
-				MemBlock* curBlock = mBlocks[i];
-				UINT8* blockEnd = curBlock->mData + curBlock->mSize;
-				if (framePtr >= curBlock->mData && framePtr < blockEnd)
-				{
-					UINT8* dataEnd = curBlock->mData + curBlock->mFreePtr;
-					UINT32 sizeInBlock = (UINT32)(dataEnd - framePtr);
-					assert(sizeInBlock <= curBlock->mFreePtr);
-
-					curBlock->mFreePtr -= sizeInBlock;
-					if (curBlock->mFreePtr == 0)
-					{
-						numFreedBlocks++;
-
-						// Reset block counter if we're gonna reallocate this one
-						if (numFreedBlocks > 1)
-							mNextBlockIdx = (UINT32)i;
-					}
-
-					break;
-				}
-				else
-				{
-					curBlock->mFreePtr = 0;
-					mNextBlockIdx = (UINT32)i;
-					numFreedBlocks++;
-				}
-			}
-
-			if (numFreedBlocks > 1)
-			{
-				UINT32 totalBytes = 0;
-				for (UINT32 i = 0; i < numFreedBlocks; i++)
-				{
-					MemBlock* curBlock = mBlocks[mNextBlockIdx];
-					totalBytes += curBlock->mSize;
-
-					deallocBlock(curBlock);
-					mBlocks.erase(mBlocks.begin() + mNextBlockIdx);
-				}
-				
-				UINT32 oldNextBlockIdx = mNextBlockIdx;
-				allocBlock(totalBytes);
-
-				// Point to the first non-full block, or if none available then point the the block we just allocated
-				if (oldNextBlockIdx > 0)
-					mFreeBlock = mBlocks[oldNextBlockIdx - 1];
-			}
-			else
-			{
-				mFreeBlock = mBlocks[mNextBlockIdx - 1];
-			}
-		}
-		else
-		{
-#if BS_DEBUG_MODE
-			if (mTotalAllocBytes.load() > 0)
-				BS_EXCEPT(InvalidStateException, "Not all frame allocated bytes were properly released.");
-#endif
-
-			if (mBlocks.size() > 1)
-			{
-				// Merge all blocks into one
-				UINT32 totalBytes = 0;
-				for (auto& block : mBlocks)
-				{
-					totalBytes += block->mSize;
-					deallocBlock(block);
-				}
-
-				mBlocks.clear();
-				mNextBlockIdx = 0;
-
-				allocBlock(totalBytes);
-			}
-		}
-	}
-
-	FrameAlloc::MemBlock* FrameAlloc::allocBlock(UINT32 wantedSize)
-	{
-		UINT32 blockSize = mBlockSize;
-		if(wantedSize > blockSize)
-			blockSize = wantedSize;
-
-		MemBlock* newBlock = nullptr;
-		while (mNextBlockIdx < mBlocks.size())
-		{
-			MemBlock* curBlock = mBlocks[mNextBlockIdx];
-			if (blockSize <= curBlock->mSize)
-			{
-				newBlock = curBlock;
-				mNextBlockIdx++;
-				break;
-			}
-			else
-			{
-				// Found an empty block that doesn't fit our data, delete it
-				deallocBlock(curBlock);
-				mBlocks.erase(mBlocks.begin() + mNextBlockIdx);
-			}
-		}
-
-		if (newBlock == nullptr)
-		{
-			UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc_aligned16(blockSize + sizeof(MemBlock)));
-			newBlock = new (data) MemBlock(blockSize);
-			data += sizeof(MemBlock);
-			newBlock->mData = data;
-
-			mBlocks.push_back(newBlock);
-			mNextBlockIdx++;
-		}
-
-		mFreeBlock = newBlock; // If previous block had some empty space it is lost until next "clear"
-
-		return newBlock;
-	}
-
-	void FrameAlloc::deallocBlock(MemBlock* block)
-	{
-		block->~MemBlock();
-		bs_free_aligned(block);
-	}
-
-	void FrameAlloc::setOwnerThread(BS_THREAD_ID_TYPE thread)
-	{
-#if BS_DEBUG_MODE
-		mOwnerThread = thread;
-#endif
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsFrameAlloc.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	FrameAlloc::MemBlock::MemBlock(UINT32 size)
+		:mData(nullptr), mFreePtr(0), mSize(size)
+	{ }
+
+	FrameAlloc::MemBlock::~MemBlock()
+	{ }
+
+	UINT8* FrameAlloc::MemBlock::alloc(UINT32 amount)
+	{
+		UINT8* freePtr = &mData[mFreePtr];
+		mFreePtr += amount;
+
+		return freePtr;
+	}
+
+	void FrameAlloc::MemBlock::clear()
+	{
+		mFreePtr = 0;
+	}
+
+#if BS_DEBUG_MODE
+	FrameAlloc::FrameAlloc(UINT32 blockSize)
+		:mBlockSize(blockSize), mFreeBlock(nullptr), mNextBlockIdx(0), mTotalAllocBytes(0),
+		mLastFrame(nullptr), mOwnerThread(BS_THREAD_CURRENT_ID)
+	{
+		allocBlock(mBlockSize);
+	}
+#else
+	FrameAlloc::FrameAlloc(UINT32 blockSize)
+		:mTotalAllocBytes(0), mFreeBlock(nullptr), mBlockSize(blockSize),
+		mLastFrame(nullptr), mNextBlockIdx(0)
+	{
+		allocBlock(mBlockSize);
+	}
+#endif
+
+	FrameAlloc::~FrameAlloc()
+	{
+		for(auto& block : mBlocks)
+			deallocBlock(block);
+	}
+
+	UINT8* FrameAlloc::alloc(UINT32 amount)
+	{
+#if BS_DEBUG_MODE
+		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
+
+		amount += sizeof(UINT32);
+#endif
+
+		UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
+		if(amount > freeMem)
+			allocBlock(amount);
+
+		UINT8* data = mFreeBlock->alloc(amount);
+
+#if BS_DEBUG_MODE
+		mTotalAllocBytes += amount;
+
+		UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+		*storedSize = amount;
+
+		return data + sizeof(UINT32);
+#else
+		return data;
+#endif
+	}
+
+	UINT8* FrameAlloc::allocAligned(UINT32 amount, UINT32 alignment)
+	{
+#if BS_DEBUG_MODE
+		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
+
+		amount += sizeof(UINT32);
+		UINT32 freePtr = mFreeBlock->mFreePtr + sizeof(UINT32);
+#else
+		UINT32 freePtr = mFreeBlock->mFreePtr;
+#endif
+
+		UINT32 alignOffset = alignment - freePtr & (alignment - 1);
+
+		UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
+		if ((amount + alignOffset) > freeMem)
+		{
+			// New blocks are allocated on a 16 byte boundary, ensure we enough space is allocated taking into account
+			// the requested alignment
+
+#if BS_DEBUG_MODE
+			alignOffset = alignment - sizeof(UINT32) & (alignment - 1);
+#else
+			if (alignment > 16)
+				alignOffset = alignment - 16;
+			else
+				alignOffset = 0;
+#endif
+
+			allocBlock(amount + alignOffset);
+		}
+
+		amount += alignOffset;
+		UINT8* data = mFreeBlock->alloc(amount);
+
+#if BS_DEBUG_MODE
+		mTotalAllocBytes += amount;
+
+		UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+		*storedSize = amount;
+
+		return data + sizeof(UINT32) + alignOffset;
+#else
+		return data + alignOffset;
+#endif
+	}
+
+	void FrameAlloc::dealloc(UINT8* data)
+	{
+		// Dealloc is only used for debug and can be removed if needed. All the actual deallocation
+		// happens in clear()
+			
+#if BS_DEBUG_MODE
+		data -= sizeof(UINT32);
+		UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+		mTotalAllocBytes -= *storedSize;
+#endif
+	}
+
+	void FrameAlloc::markFrame()
+	{
+		void** framePtr = (void**)alloc(sizeof(void*));
+		*framePtr = mLastFrame;
+		mLastFrame = framePtr;
+	}
+
+	void FrameAlloc::clear()
+	{
+#if BS_DEBUG_MODE
+		assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
+#endif
+
+		if(mLastFrame != nullptr)
+		{
+			assert(mBlocks.size() > 0 && mNextBlockIdx > 0);
+
+			dealloc((UINT8*)mLastFrame);
+
+			UINT8* framePtr = (UINT8*)mLastFrame;
+			mLastFrame = *(void**)mLastFrame;
+
+#if BS_DEBUG_MODE
+			framePtr -= sizeof(UINT32);
+#endif
+
+			UINT32 startBlockIdx = mNextBlockIdx - 1;
+			UINT32 numFreedBlocks = 0;
+			for (INT32 i = startBlockIdx; i >= 0; i--)
+			{
+				MemBlock* curBlock = mBlocks[i];
+				UINT8* blockEnd = curBlock->mData + curBlock->mSize;
+				if (framePtr >= curBlock->mData && framePtr < blockEnd)
+				{
+					UINT8* dataEnd = curBlock->mData + curBlock->mFreePtr;
+					UINT32 sizeInBlock = (UINT32)(dataEnd - framePtr);
+					assert(sizeInBlock <= curBlock->mFreePtr);
+
+					curBlock->mFreePtr -= sizeInBlock;
+					if (curBlock->mFreePtr == 0)
+					{
+						numFreedBlocks++;
+
+						// Reset block counter if we're gonna reallocate this one
+						if (numFreedBlocks > 1)
+							mNextBlockIdx = (UINT32)i;
+					}
+
+					break;
+				}
+				else
+				{
+					curBlock->mFreePtr = 0;
+					mNextBlockIdx = (UINT32)i;
+					numFreedBlocks++;
+				}
+			}
+
+			if (numFreedBlocks > 1)
+			{
+				UINT32 totalBytes = 0;
+				for (UINT32 i = 0; i < numFreedBlocks; i++)
+				{
+					MemBlock* curBlock = mBlocks[mNextBlockIdx];
+					totalBytes += curBlock->mSize;
+
+					deallocBlock(curBlock);
+					mBlocks.erase(mBlocks.begin() + mNextBlockIdx);
+				}
+				
+				UINT32 oldNextBlockIdx = mNextBlockIdx;
+				allocBlock(totalBytes);
+
+				// Point to the first non-full block, or if none available then point the the block we just allocated
+				if (oldNextBlockIdx > 0)
+					mFreeBlock = mBlocks[oldNextBlockIdx - 1];
+			}
+			else
+			{
+				mFreeBlock = mBlocks[mNextBlockIdx - 1];
+			}
+		}
+		else
+		{
+#if BS_DEBUG_MODE
+			if (mTotalAllocBytes.load() > 0)
+				BS_EXCEPT(InvalidStateException, "Not all frame allocated bytes were properly released.");
+#endif
+
+			if (mBlocks.size() > 1)
+			{
+				// Merge all blocks into one
+				UINT32 totalBytes = 0;
+				for (auto& block : mBlocks)
+				{
+					totalBytes += block->mSize;
+					deallocBlock(block);
+				}
+
+				mBlocks.clear();
+				mNextBlockIdx = 0;
+
+				allocBlock(totalBytes);
+			}
+		}
+	}
+
+	FrameAlloc::MemBlock* FrameAlloc::allocBlock(UINT32 wantedSize)
+	{
+		UINT32 blockSize = mBlockSize;
+		if(wantedSize > blockSize)
+			blockSize = wantedSize;
+
+		MemBlock* newBlock = nullptr;
+		while (mNextBlockIdx < mBlocks.size())
+		{
+			MemBlock* curBlock = mBlocks[mNextBlockIdx];
+			if (blockSize <= curBlock->mSize)
+			{
+				newBlock = curBlock;
+				mNextBlockIdx++;
+				break;
+			}
+			else
+			{
+				// Found an empty block that doesn't fit our data, delete it
+				deallocBlock(curBlock);
+				mBlocks.erase(mBlocks.begin() + mNextBlockIdx);
+			}
+		}
+
+		if (newBlock == nullptr)
+		{
+			UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc_aligned16(blockSize + sizeof(MemBlock)));
+			newBlock = new (data) MemBlock(blockSize);
+			data += sizeof(MemBlock);
+			newBlock->mData = data;
+
+			mBlocks.push_back(newBlock);
+			mNextBlockIdx++;
+		}
+
+		mFreeBlock = newBlock; // If previous block had some empty space it is lost until next "clear"
+
+		return newBlock;
+	}
+
+	void FrameAlloc::deallocBlock(MemBlock* block)
+	{
+		block->~MemBlock();
+		bs_free_aligned(block);
+	}
+
+	void FrameAlloc::setOwnerThread(BS_THREAD_ID_TYPE thread)
+	{
+#if BS_DEBUG_MODE
+		mOwnerThread = thread;
+#endif
+	}
 }

+ 176 - 176
Source/MBansheeEditor/AboutBox.cs

@@ -1,176 +1,176 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Displays information about the engine, its creator and licenses.
-    /// </summary>
-    public class AboutBox : ModalWindow
-    {
-        private GUITextBox emailLabel;
-
-        /// <summary>
-        /// Opens the about box.
-        /// </summary>
-        [MenuItem("Help/About", 5000)]
-        public static void Open()
-        {
-            new AboutBox();
-        }
-
-        /// <summary>
-        /// Constructs the about box.
-        /// </summary>
-        protected AboutBox()
-            : base(true)
-        {
-            Title = "About";
-            Width = 400;
-            Height = 400;
-        }
-
-        private void OnInitialize()
-        {
-            GUILabel title = new GUILabel(new LocEdString("Banshee Engine v0.2"), EditorStyles.TitleLabel);
-            GUILabel subTitle = new GUILabel(new LocEdString("A modern open-source game development toolkit"), 
-                EditorStyles.LabelCentered);
-            GUILabel license = new GUILabel(new LocEdString(
-                "This program is licensed under the GNU General Public License V3"), EditorStyles.LabelCentered);
-            GUILabel copyright = new GUILabel(new LocEdString("Copyright (C) 2015 Marko Pintera. All rights reserved."), 
-                EditorStyles.LabelCentered);
-            GUILabel emailTitle = new GUILabel(new LocEdString("E-mail"), GUIOption.FixedWidth(150));
-            emailLabel = new GUITextBox();
-            GUILabel linkedInTitle = new GUILabel(new LocEdString("LinkedIn"), GUIOption.FixedWidth(150));
-            GUIButton linkedInBtn = new GUIButton(new LocEdString("Profile"));
-
-            GUIToggleGroup foldoutGroup = new GUIToggleGroup(true);
-            GUIToggle contactFoldout = new GUIToggle(new LocEdString("Author contact"), foldoutGroup, EditorStyles.Foldout);
-            GUIToggle thirdPartyFoldout = new GUIToggle(new LocEdString("Used third party libraries"), foldoutGroup, EditorStyles.Foldout);
-            GUIToggle noticesFoldout = new GUIToggle(new LocEdString("Third party notices"), foldoutGroup, EditorStyles.Foldout);
-            GUIToggle collaboratorsFoldout = new GUIToggle(new LocEdString("Collaborators"), foldoutGroup, EditorStyles.Foldout);
-
-            GUILabel freeTypeNotice = new GUILabel(new LocEdString(
-                        "Portions of this software are copyright (C) 2015 The FreeType Project (www.freetype.org). " +
-                        "All rights reserved."), EditorStyles.MultiLineLabelCentered, 
-                        GUIOption.FlexibleHeight(), GUIOption.FixedWidth(380));
-
-            GUILabel fbxSdkNotice = new GUILabel(new LocEdString(
-                "This software contains Autodesk(R) FBX(R) code developed by Autodesk, Inc. Copyright 2013 Autodesk, Inc. " +
-                "All rights, reserved. Such code is provided \"as is\" and Autodesk, Inc. disclaims any and all warranties, " +
-                "whether express or implied, including without limitation the implied warranties of merchantability, " +
-                "fitness for a particular purpose or non-infringement of third party rights. In no event shall Autodesk, " +
-                "Inc. be liable for any direct, indirect, incidental, special, exemplary, or consequential damages " +
-                "(including, but not limited to, procurement of substitute goods or services; loss of use, data, or " +
-                "profits; or business interruption) however caused and on any theory of liability, whether in contract, " +
-                "strict liability, or tort (including negligence or otherwise) arising in any way out of such code."),
-                EditorStyles.MultiLineLabelCentered, GUIOption.FlexibleHeight(), GUIOption.FixedWidth(380));
-
-            GUILayoutY mainLayout = GUI.AddLayoutY();
-            mainLayout.AddSpace(10);
-            mainLayout.AddElement(title);
-            mainLayout.AddElement(subTitle);
-            mainLayout.AddSpace(10);
-            mainLayout.AddElement(license);
-            mainLayout.AddElement(copyright);
-            mainLayout.AddSpace(10);
-            mainLayout.AddElement(contactFoldout);
-
-            GUILayoutY contactLayout = mainLayout.AddLayoutY();
-            GUILayout emailLayout = contactLayout.AddLayoutX();
-            emailLayout.AddSpace(10);
-            emailLayout.AddElement(emailTitle);
-            emailLayout.AddElement(emailLabel);
-            emailLayout.AddSpace(10);
-            GUILayout linkedInLayout = contactLayout.AddLayoutX();
-            linkedInLayout.AddSpace(10);
-            linkedInLayout.AddElement(linkedInTitle);
-            linkedInLayout.AddElement(linkedInBtn);
-            linkedInLayout.AddSpace(10);
-
-            mainLayout.AddSpace(5);
-            mainLayout.AddElement(thirdPartyFoldout);
-            GUILayoutY thirdPartyLayout = mainLayout.AddLayoutY();
-
-            CreateThirdPartyGUI(thirdPartyLayout, "Autodesk FBX SDK",
-                "http://usa.autodesk.com/adsk/servlet/pc/item?siteID=123112&id=10775847", "FBX_SDK_License.rtf");
-            CreateThirdPartyGUI(thirdPartyLayout, "FreeImage", "http://freeimage.sourceforge.net/", "freeimage-license.txt");
-            CreateThirdPartyGUI(thirdPartyLayout, "FreeType", "http://www.freetype.org/", "FTL.TXT");
-            CreateThirdPartyGUI(thirdPartyLayout, "Mono", "http://www.mono-project.com/", "Mono.txt");
-            CreateThirdPartyGUI(thirdPartyLayout, "NVIDIA Texture Tools",
-                "https://github.com/castano/nvidia-texture-tools", "NVIDIATextureTools.txt");
-
-            mainLayout.AddSpace(5);
-            mainLayout.AddElement(noticesFoldout);
-            GUILayout noticesLayout = mainLayout.AddLayoutY();
-            noticesLayout.AddElement(freeTypeNotice);
-            noticesLayout.AddSpace(10);
-            noticesLayout.AddElement(fbxSdkNotice);
-
-            mainLayout.AddSpace(5);
-            mainLayout.AddElement(collaboratorsFoldout);
-            GUILayoutY collaboratorsLayout = mainLayout.AddLayoutY();
-            CreateCollaboratorGUI(collaboratorsLayout, "Danijel Ribic", "Logo, UI icons, 3D models & textures");
-
-            mainLayout.AddFlexibleSpace();
-
-            contactLayout.Active = false;
-            contactFoldout.OnToggled += x =>
-            {
-                contactLayout.Active = x;
-            };
-
-            thirdPartyLayout.Active = false;
-            thirdPartyFoldout.OnToggled += x => thirdPartyLayout.Active = x;
-
-            noticesLayout.Active = false;
-            noticesFoldout.OnToggled += x => noticesLayout.Active = x;
-
-            collaboratorsLayout.Active = false;
-            collaboratorsFoldout.OnToggled += x => collaboratorsLayout.Active = x;
-
-            emailLabel.Text = "[email protected]";
-            linkedInBtn.OnClick += () => { System.Diagnostics.Process.Start("http://hr.linkedin.com/in/markopintera"); };
-        }
-
-        private void CreateThirdPartyGUI(GUILayoutY layout, string name, string webURL, string licenseFile)
-        {
-            GUILabel label = new GUILabel(new LocEdString(name), GUIOption.FixedWidth(150));
-            GUIButton linkBtn = new GUIButton(new LocEdString("Website"), GUIOption.FixedWidth(50));
-            GUIButton licenseBtn = new GUIButton(new LocEdString("License"), GUIOption.FixedWidth(50));
-
-            string licensePath = "..\\..\\..\\License\\Third Party\\" + licenseFile;
-
-            GUILayoutX horzLayout = layout.AddLayoutX();
-            horzLayout.AddSpace(10);
-            horzLayout.AddElement(label);
-            horzLayout.AddSpace(10);
-            horzLayout.AddElement(linkBtn);
-            horzLayout.AddSpace(5);
-            horzLayout.AddElement(licenseBtn);
-            horzLayout.AddSpace(10);
-
-            linkBtn.OnClick += () => { System.Diagnostics.Process.Start(webURL); };
-            licenseBtn.OnClick += () => { System.Diagnostics.Process.Start(licensePath); };
-        }
-
-        private void CreateCollaboratorGUI(GUILayoutY layout, string name, string area)
-        {
-            GUILabel nameLabel = new GUILabel(new LocEdString(name), GUIOption.FixedWidth(150));
-            GUILabel areaLabel = new GUILabel(new LocEdString(area), GUIOption.FixedWidth(220));
-
-            GUILayoutX horzLayout = layout.AddLayoutX();
-            horzLayout.AddSpace(10);
-            horzLayout.AddElement(nameLabel);
-            horzLayout.AddSpace(10);
-            horzLayout.AddElement(areaLabel);
-            horzLayout.AddSpace(10);
-        }
-
-        private void OnEditorUpdate()
-        {
-            emailLabel.Text = "[email protected]";
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Displays information about the engine, its creator and licenses.
+    /// </summary>
+    public class AboutBox : ModalWindow
+    {
+        private GUITextBox emailLabel;
+
+        /// <summary>
+        /// Opens the about box.
+        /// </summary>
+        [MenuItem("Help/About", 5000)]
+        public static void Open()
+        {
+            new AboutBox();
+        }
+
+        /// <summary>
+        /// Constructs the about box.
+        /// </summary>
+        protected AboutBox()
+            : base(true)
+        {
+            Title = "About";
+            Width = 400;
+            Height = 400;
+        }
+
+        private void OnInitialize()
+        {
+            GUILabel title = new GUILabel(new LocEdString("Banshee Engine v0.3"), EditorStyles.TitleLabel);
+            GUILabel subTitle = new GUILabel(new LocEdString("A modern open-source game development toolkit"), 
+                EditorStyles.LabelCentered);
+            GUILabel license = new GUILabel(new LocEdString(
+                "This program is licensed under the GNU General Public License V3"), EditorStyles.LabelCentered);
+            GUILabel copyright = new GUILabel(new LocEdString("Copyright (C) 2015 Marko Pintera. All rights reserved."), 
+                EditorStyles.LabelCentered);
+            GUILabel emailTitle = new GUILabel(new LocEdString("E-mail"), GUIOption.FixedWidth(150));
+            emailLabel = new GUITextBox();
+            GUILabel linkedInTitle = new GUILabel(new LocEdString("LinkedIn"), GUIOption.FixedWidth(150));
+            GUIButton linkedInBtn = new GUIButton(new LocEdString("Profile"));
+
+            GUIToggleGroup foldoutGroup = new GUIToggleGroup(true);
+            GUIToggle contactFoldout = new GUIToggle(new LocEdString("Author contact"), foldoutGroup, EditorStyles.Foldout);
+            GUIToggle thirdPartyFoldout = new GUIToggle(new LocEdString("Used third party libraries"), foldoutGroup, EditorStyles.Foldout);
+            GUIToggle noticesFoldout = new GUIToggle(new LocEdString("Third party notices"), foldoutGroup, EditorStyles.Foldout);
+            GUIToggle collaboratorsFoldout = new GUIToggle(new LocEdString("Collaborators"), foldoutGroup, EditorStyles.Foldout);
+
+            GUILabel freeTypeNotice = new GUILabel(new LocEdString(
+                        "Portions of this software are copyright (C) 2015 The FreeType Project (www.freetype.org). " +
+                        "All rights reserved."), EditorStyles.MultiLineLabelCentered, 
+                        GUIOption.FlexibleHeight(), GUIOption.FixedWidth(380));
+
+            GUILabel fbxSdkNotice = new GUILabel(new LocEdString(
+                "This software contains Autodesk(R) FBX(R) code developed by Autodesk, Inc. Copyright 2013 Autodesk, Inc. " +
+                "All rights, reserved. Such code is provided \"as is\" and Autodesk, Inc. disclaims any and all warranties, " +
+                "whether express or implied, including without limitation the implied warranties of merchantability, " +
+                "fitness for a particular purpose or non-infringement of third party rights. In no event shall Autodesk, " +
+                "Inc. be liable for any direct, indirect, incidental, special, exemplary, or consequential damages " +
+                "(including, but not limited to, procurement of substitute goods or services; loss of use, data, or " +
+                "profits; or business interruption) however caused and on any theory of liability, whether in contract, " +
+                "strict liability, or tort (including negligence or otherwise) arising in any way out of such code."),
+                EditorStyles.MultiLineLabelCentered, GUIOption.FlexibleHeight(), GUIOption.FixedWidth(380));
+
+            GUILayoutY mainLayout = GUI.AddLayoutY();
+            mainLayout.AddSpace(10);
+            mainLayout.AddElement(title);
+            mainLayout.AddElement(subTitle);
+            mainLayout.AddSpace(10);
+            mainLayout.AddElement(license);
+            mainLayout.AddElement(copyright);
+            mainLayout.AddSpace(10);
+            mainLayout.AddElement(contactFoldout);
+
+            GUILayoutY contactLayout = mainLayout.AddLayoutY();
+            GUILayout emailLayout = contactLayout.AddLayoutX();
+            emailLayout.AddSpace(10);
+            emailLayout.AddElement(emailTitle);
+            emailLayout.AddElement(emailLabel);
+            emailLayout.AddSpace(10);
+            GUILayout linkedInLayout = contactLayout.AddLayoutX();
+            linkedInLayout.AddSpace(10);
+            linkedInLayout.AddElement(linkedInTitle);
+            linkedInLayout.AddElement(linkedInBtn);
+            linkedInLayout.AddSpace(10);
+
+            mainLayout.AddSpace(5);
+            mainLayout.AddElement(thirdPartyFoldout);
+            GUILayoutY thirdPartyLayout = mainLayout.AddLayoutY();
+
+            CreateThirdPartyGUI(thirdPartyLayout, "Autodesk FBX SDK",
+                "http://usa.autodesk.com/adsk/servlet/pc/item?siteID=123112&id=10775847", "FBX_SDK_License.rtf");
+            CreateThirdPartyGUI(thirdPartyLayout, "FreeImage", "http://freeimage.sourceforge.net/", "freeimage-license.txt");
+            CreateThirdPartyGUI(thirdPartyLayout, "FreeType", "http://www.freetype.org/", "FTL.TXT");
+            CreateThirdPartyGUI(thirdPartyLayout, "Mono", "http://www.mono-project.com/", "Mono.txt");
+            CreateThirdPartyGUI(thirdPartyLayout, "NVIDIA Texture Tools",
+                "https://github.com/castano/nvidia-texture-tools", "NVIDIATextureTools.txt");
+
+            mainLayout.AddSpace(5);
+            mainLayout.AddElement(noticesFoldout);
+            GUILayout noticesLayout = mainLayout.AddLayoutY();
+            noticesLayout.AddElement(freeTypeNotice);
+            noticesLayout.AddSpace(10);
+            noticesLayout.AddElement(fbxSdkNotice);
+
+            mainLayout.AddSpace(5);
+            mainLayout.AddElement(collaboratorsFoldout);
+            GUILayoutY collaboratorsLayout = mainLayout.AddLayoutY();
+            CreateCollaboratorGUI(collaboratorsLayout, "Danijel Ribic", "Logo, UI icons, 3D models & textures");
+
+            mainLayout.AddFlexibleSpace();
+
+            contactLayout.Active = false;
+            contactFoldout.OnToggled += x =>
+            {
+                contactLayout.Active = x;
+            };
+
+            thirdPartyLayout.Active = false;
+            thirdPartyFoldout.OnToggled += x => thirdPartyLayout.Active = x;
+
+            noticesLayout.Active = false;
+            noticesFoldout.OnToggled += x => noticesLayout.Active = x;
+
+            collaboratorsLayout.Active = false;
+            collaboratorsFoldout.OnToggled += x => collaboratorsLayout.Active = x;
+
+            emailLabel.Text = "[email protected]";
+            linkedInBtn.OnClick += () => { System.Diagnostics.Process.Start("http://hr.linkedin.com/in/markopintera"); };
+        }
+
+        private void CreateThirdPartyGUI(GUILayoutY layout, string name, string webURL, string licenseFile)
+        {
+            GUILabel label = new GUILabel(new LocEdString(name), GUIOption.FixedWidth(150));
+            GUIButton linkBtn = new GUIButton(new LocEdString("Website"), GUIOption.FixedWidth(50));
+            GUIButton licenseBtn = new GUIButton(new LocEdString("License"), GUIOption.FixedWidth(50));
+
+            string licensePath = "..\\..\\..\\License\\Third Party\\" + licenseFile;
+
+            GUILayoutX horzLayout = layout.AddLayoutX();
+            horzLayout.AddSpace(10);
+            horzLayout.AddElement(label);
+            horzLayout.AddSpace(10);
+            horzLayout.AddElement(linkBtn);
+            horzLayout.AddSpace(5);
+            horzLayout.AddElement(licenseBtn);
+            horzLayout.AddSpace(10);
+
+            linkBtn.OnClick += () => { System.Diagnostics.Process.Start(webURL); };
+            licenseBtn.OnClick += () => { System.Diagnostics.Process.Start(licensePath); };
+        }
+
+        private void CreateCollaboratorGUI(GUILayoutY layout, string name, string area)
+        {
+            GUILabel nameLabel = new GUILabel(new LocEdString(name), GUIOption.FixedWidth(150));
+            GUILabel areaLabel = new GUILabel(new LocEdString(area), GUIOption.FixedWidth(220));
+
+            GUILayoutX horzLayout = layout.AddLayoutX();
+            horzLayout.AddSpace(10);
+            horzLayout.AddElement(nameLabel);
+            horzLayout.AddSpace(10);
+            horzLayout.AddElement(areaLabel);
+            horzLayout.AddSpace(10);
+        }
+
+        private void OnEditorUpdate()
+        {
+            emailLabel.Text = "[email protected]";
+        }
+    }
+}

+ 621 - 621
Source/MBansheeEditor/MenuItems.cs

@@ -1,621 +1,621 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Contains various menu item callbacks for the main editor menu bar.
-    /// </summary>
-    static class MenuItems
-    {
-        /// <summary>
-        /// Adds a camera component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Camera", 7050)]
-        private static void AddCamera()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a Camera component");
-            Camera cam = so.AddComponent<Camera>();
-            cam.Main = true;
-
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a renderable component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Renderable", 7049)]
-        private static void AddRenderable()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a Renderable component");
-            so.AddComponent<Renderable>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a point light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Point light", 7048)]
-        private static void AddPointLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Point;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a spot light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Spot light", 7047)]
-        private static void AddSpotLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Spot;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a directional light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Directional light", 7046)]
-        private static void AddDirectionalLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Directional;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a GUI widget component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/GUI widget", 7045)]
-        private static void AddGUIWidget()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, false, "Added a GUIWidget component");
-            so.AddComponent<GUIWidget>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a BoxCollider component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Box collider", 7044)]
-        private static void AddBoxCollider()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("BoxCollider", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a BoxCollider component");
-            so.AddComponent<BoxCollider>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a SphereCollider component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Sphere collider", 7043)]
-        private static void AddSphereCollider()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("SphereCollider", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a SphereCollider component");
-            so.AddComponent<SphereCollider>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a CapsuleCollider component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Capsule collider", 7042)]
-        private static void AddCapsuleCollider()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("CapsuleCollider", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a CapsuleCollider component");
-            so.AddComponent<CapsuleCollider>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a MeshCollider component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Mesh collider", 7041)]
-        private static void AddMeshCollider()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("MeshCollider", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a MeshCollider component");
-            so.AddComponent<MeshCollider>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a PlaneCollider component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Plane collider", 7040)]
-        private static void AddPlaneCollider()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("PlaneCollider", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a PlaneCollider component");
-            so.AddComponent<PlaneCollider>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a Rigidbody component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Rigidbody", 7039, true)]
-        private static void AddRigidbody()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("Rigidbody", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a Rigidbody component");
-            so.AddComponent<Rigidbody>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a CharacterController component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Character controller", 7038)]
-        private static void AddCharacterController()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("CharacterController", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a CharacterController component");
-            so.AddComponent<CharacterController>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a FixedJoint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Fixed joint", 7037, true)]
-        private static void AddFixedJoint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("FixedJoint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a FixedJoint component");
-            so.AddComponent<FixedJoint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a DistanceJoint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Distance joint", 7036)]
-        private static void AddDistanceJoint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("DistanceJoint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a DistanceJoint component");
-            so.AddComponent<DistanceJoint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a HingeJoint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Hinge joint", 7035)]
-        private static void AddHingeJoint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("HingeJoint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a HingeJoint component");
-            so.AddComponent<HingeJoint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a SphericalJoint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Spherical joint", 7034)]
-        private static void AddSphericalJoint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("SphericalJoint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a SphericalJoint component");
-            so.AddComponent<SphericalJoint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a SliderJoint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/Slider joint", 7032)]
-        private static void AddSliderJoint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("SliderJoint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a SliderJoint component");
-            so.AddComponent<SliderJoint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a D6Joint component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Physics/D6 joint", 7032)]
-        private static void AddD6Joint()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                so = UndoRedo.CreateSO("D6Joint", "New scene object");
-
-            UndoRedo.RecordSO(so, false, "Added a D6Joint component");
-            so.AddComponent<D6Joint>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new empty scene object.
-        /// </summary>
-        [MenuItem("Scene Objects/Scene Object", 8051)]
-        [ToolbarItem("SceneObject", ToolbarIcon.NewSceneObject, "Creates a new empty scene object", 1601, true)]
-        private static void AddEmptySO()
-        {
-            SceneObject so = UndoRedo.CreateSO("SceneObject", "New scene object");
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a camera component.
-        /// </summary>
-        [MenuItem("Scene Objects/Camera", 8050)]
-        [ToolbarItem("Camera", ToolbarIcon.NewCamera, "New camera", 1600, false)]
-        private static void AddCameraSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Camera", "Created a Camera");
-            Camera cam = so.AddComponent<Camera>();
-            cam.Main = true;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a renderable component.
-        /// </summary>
-        [MenuItem("Scene Objects/Renderable", 8049)]
-        [ToolbarItem("Renderable", ToolbarIcon.NewRenderable, "New renderable", 1599)]
-        private static void AddRenderableSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Renderable", "Created a Renderable");
-            so.AddComponent<Renderable>();
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a point light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Point light", 8048)]
-        [ToolbarItem("Point light", ToolbarIcon.NewPointLight, "New point light", 1598)]
-        private static void AddPointLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Point light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Point;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a spot light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Spot light", 8047)]
-        [ToolbarItem("Spot light", ToolbarIcon.NewSpotLight, "New spot light", 1597)]
-        private static void AddSpotLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Spot light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Spot;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a directional light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Directional light", 8046)]
-        [ToolbarItem("Directional light", ToolbarIcon.NewDirLight, "New directional light", 1596)]
-        private static void AddDirectionalLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Directional light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Directional;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a GUI widget component.
-        /// </summary>
-        [MenuItem("Scene Objects/GUI widget", 8045)]
-        private static void AddGUIWidgetSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("GUIWidget", "Created a GUIWidget");
-            so.AddComponent<GUIWidget>();
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a box primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Box", 8100)]
-        [ToolbarItem("Cube", ToolbarIcon.NewCube, "Creates a scene object with a box primitive", 1700, true)]
-        private static void Add3DBox()
-        {
-            SceneObject so = UndoRedo.CreateSO("Box", "Created a box");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Box;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a sphere primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Sphere", 8099)]
-        [ToolbarItem("Sphere", ToolbarIcon.NewSphere, "Creates a scene object with a sphere primitive", 1699)]
-        private static void Add3DSphere()
-        {
-            SceneObject so = UndoRedo.CreateSO("Sphere", "Created a sphere");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Sphere;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a cone primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Cone", 8098)]
-        [ToolbarItem("Cone", ToolbarIcon.NewCone, "Creates a scene object with a cone primitive", 1698)]
-        private static void Add3DCone()
-        {
-            SceneObject so = UndoRedo.CreateSO("Cone", "Created a cone");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Cone;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a quad primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Quad", 8097)]
-        [ToolbarItem("Quad", ToolbarIcon.NewQuad, "Creates a scene object with a quad primitive", 1697)]
-        private static void Add3DQuad()
-        {
-            SceneObject so = UndoRedo.CreateSO("Quad", "Created a quad");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Quad;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a disc primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Disc", 8096)]
-        private static void Add3DDisc()
-        {
-            SceneObject so = UndoRedo.CreateSO("Disc", "Created a disc");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Disc;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Applies changes from the prefab instance to the prefab resource.
-        /// </summary>
-        [MenuItem("Scene Objects/Apply prefab", 8025, true)]
-        private static void ApplyPrefab()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            PrefabUtility.ApplyPrefab(so);
-        }
-
-        /// <summary>
-        /// Reverts a prefab instance to the original state of its prefab.
-        /// </summary>
-        [MenuItem("Scene Objects/Revert to prefab", 8024)]
-        private static void RevertToPrefab()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, true, "Reverting \"" + so.Name + "\" to prefab.");
-
-            PrefabUtility.RevertPrefab(so);
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Breaks a link between a prefab and its instance.
-        /// </summary>
-        [MenuItem("Scene Objects/Break prefab link", 8023)]
-        private static void BreakPrefabLink()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.BreakPrefab(so, "Breaking prefab link for " + so.Name);
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Cuts the currently selected scene object or resource.
-        /// </summary>
-        [MenuItem("Edit/Cut", 9450, true)]
-        public static void Cut()
-        {
-            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
-            {
-                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
-                if (win != null)
-                    win.CutSelection();
-            }
-            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
-            {
-                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-                if (win != null)
-                    win.CutSelection();
-            }
-        }
-
-        /// <summary>
-        /// Copies the currently selected scene object or resource.
-        /// </summary>
-        [MenuItem("Edit/Copy", 9449)]
-        public static void Copy()
-        {
-            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
-            {
-                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
-                if (win != null)
-                    win.CopySelection();
-            }
-            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
-            {
-                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-                if (win != null)
-                    win.CopySelection();
-            }
-        }
-
-        /// <summary>
-        /// Pastes the scene objects or resources that were previously cut or copied.
-        /// </summary>
-        [MenuItem("Edit/Paste", 9448)]
-        public static void Paste()
-        {
-            // TODO - This is slightly wrong in case both windows have something in their paste buffer (unify them?)
-
-            {
-                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
-                if (win != null)
-                    win.PasteToSelection();
-            }
-
-            {
-                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-                if (win != null)
-                    win.PasteToSelection();
-            }
-        }
-
-        /// <summary>
-        /// Deletes currently selected scene objects or resources.
-        /// </summary>
-        [MenuItem("Edit/Delete", 9447)]
-        public static void Delete()
-        {
-            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
-            {
-                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
-                if (win != null)
-                    win.DeleteSelection();
-            }
-            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
-            {
-                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-                if (win != null)
-                    win.DeleteSelection();
-            }
-        }
-
-        /// <summary>
-        /// Duplicates currently selected scene objects or resources.
-        /// </summary>
-        [MenuItem("Edit/Duplicate", 9446)]
-        public static void Duplicate()
-        {
-            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
-            {
-                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
-                if (win != null)
-                    win.DuplicateSelection();
-            }
-            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
-            {
-                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-                if (win != null)
-                    win.DuplicateSelection();
-            }
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains various menu item callbacks for the main editor menu bar.
+    /// </summary>
+    static class MenuItems
+    {
+        /// <summary>
+        /// Adds a camera component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Camera", 7050)]
+        private static void AddCamera()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a Camera component");
+            Camera cam = so.AddComponent<Camera>();
+            cam.Main = true;
+
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a renderable component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Renderable", 7049)]
+        private static void AddRenderable()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a Renderable component");
+            so.AddComponent<Renderable>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a point light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Point light", 7048)]
+        private static void AddPointLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Point;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a spot light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Spot light", 7047)]
+        private static void AddSpotLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Spot;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a directional light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Directional light", 7046)]
+        private static void AddDirectionalLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Directional;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a GUI widget component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/GUI widget", 7045)]
+        private static void AddGUIWidget()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added a GUIWidget component");
+            so.AddComponent<GUIWidget>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a BoxCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Box collider", 7044)]
+        private static void AddBoxCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("BoxCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a BoxCollider component");
+            so.AddComponent<BoxCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SphereCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Sphere collider", 7043)]
+        private static void AddSphereCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SphereCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SphereCollider component");
+            so.AddComponent<SphereCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a CapsuleCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Capsule collider", 7042)]
+        private static void AddCapsuleCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("CapsuleCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a CapsuleCollider component");
+            so.AddComponent<CapsuleCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a MeshCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Mesh collider", 7041)]
+        private static void AddMeshCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("MeshCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a MeshCollider component");
+            so.AddComponent<MeshCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a PlaneCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Plane collider", 7040)]
+        private static void AddPlaneCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("PlaneCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a PlaneCollider component");
+            so.AddComponent<PlaneCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a Rigidbody component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Rigidbody", 7039, true)]
+        private static void AddRigidbody()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("Rigidbody", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a Rigidbody component");
+            so.AddComponent<Rigidbody>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a CharacterController component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Character controller", 7038)]
+        private static void AddCharacterController()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("CharacterController", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a CharacterController component");
+            so.AddComponent<CharacterController>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a FixedJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Fixed joint", 7037, true)]
+        private static void AddFixedJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("FixedJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a FixedJoint component");
+            so.AddComponent<FixedJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a DistanceJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Distance joint", 7036)]
+        private static void AddDistanceJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("DistanceJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a DistanceJoint component");
+            so.AddComponent<DistanceJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a HingeJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Hinge joint", 7035)]
+        private static void AddHingeJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("HingeJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a HingeJoint component");
+            so.AddComponent<HingeJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SphericalJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Spherical joint", 7034)]
+        private static void AddSphericalJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SphericalJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SphericalJoint component");
+            so.AddComponent<SphericalJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SliderJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Slider joint", 7032)]
+        private static void AddSliderJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SliderJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SliderJoint component");
+            so.AddComponent<SliderJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a D6Joint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/D6 joint", 7032)]
+        private static void AddD6Joint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("D6Joint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a D6Joint component");
+            so.AddComponent<D6Joint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new empty scene object.
+        /// </summary>
+        [MenuItem("Scene Objects/Scene Object", 8051)]
+        [ToolbarItem("SceneObject", ToolbarIcon.NewSceneObject, "Creates a new empty scene object", 1601, true)]
+        private static void AddEmptySO()
+        {
+            SceneObject so = UndoRedo.CreateSO("SceneObject", "New scene object");
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a camera component.
+        /// </summary>
+        [MenuItem("Scene Objects/Camera", 8050)]
+        [ToolbarItem("Camera", ToolbarIcon.NewCamera, "New camera", 1600, false)]
+        private static void AddCameraSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Camera", "Created a Camera");
+            Camera cam = so.AddComponent<Camera>();
+            cam.Main = true;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a renderable component.
+        /// </summary>
+        [MenuItem("Scene Objects/Renderable", 8049)]
+        [ToolbarItem("Renderable", ToolbarIcon.NewRenderable, "New renderable", 1599)]
+        private static void AddRenderableSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Renderable", "Created a Renderable");
+            so.AddComponent<Renderable>();
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a point light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Point light", 8048)]
+        [ToolbarItem("Point light", ToolbarIcon.NewPointLight, "New point light", 1598)]
+        private static void AddPointLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Point light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Point;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a spot light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Spot light", 8047)]
+        [ToolbarItem("Spot light", ToolbarIcon.NewSpotLight, "New spot light", 1597)]
+        private static void AddSpotLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Spot light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Spot;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a directional light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Directional light", 8046)]
+        [ToolbarItem("Directional light", ToolbarIcon.NewDirLight, "New directional light", 1596)]
+        private static void AddDirectionalLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Directional light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Directional;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a GUI widget component.
+        /// </summary>
+        [MenuItem("Scene Objects/GUI widget", 8045)]
+        private static void AddGUIWidgetSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("GUIWidget", "Created a GUIWidget");
+            so.AddComponent<GUIWidget>();
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a box primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Box", 8100)]
+        [ToolbarItem("Cube", ToolbarIcon.NewCube, "Creates a scene object with a box primitive", 1700, true)]
+        private static void Add3DBox()
+        {
+            SceneObject so = UndoRedo.CreateSO("Box", "Created a box");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Box;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a sphere primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Sphere", 8099)]
+        [ToolbarItem("Sphere", ToolbarIcon.NewSphere, "Creates a scene object with a sphere primitive", 1699)]
+        private static void Add3DSphere()
+        {
+            SceneObject so = UndoRedo.CreateSO("Sphere", "Created a sphere");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Sphere;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a cone primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Cone", 8098)]
+        [ToolbarItem("Cone", ToolbarIcon.NewCone, "Creates a scene object with a cone primitive", 1698)]
+        private static void Add3DCone()
+        {
+            SceneObject so = UndoRedo.CreateSO("Cone", "Created a cone");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Cone;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a quad primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Quad", 8097)]
+        [ToolbarItem("Quad", ToolbarIcon.NewQuad, "Creates a scene object with a quad primitive", 1697)]
+        private static void Add3DQuad()
+        {
+            SceneObject so = UndoRedo.CreateSO("Quad", "Created a quad");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Quad;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a disc primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Disc", 8096)]
+        private static void Add3DDisc()
+        {
+            SceneObject so = UndoRedo.CreateSO("Disc", "Created a disc");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Disc;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Applies changes from the prefab instance to the prefab resource.
+        /// </summary>
+        [MenuItem("Scene Objects/Apply prefab", 8025, true)]
+        private static void ApplyPrefab()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            PrefabUtility.ApplyPrefab(so);
+        }
+
+        /// <summary>
+        /// Reverts a prefab instance to the original state of its prefab.
+        /// </summary>
+        [MenuItem("Scene Objects/Revert to prefab", 8024)]
+        private static void RevertToPrefab()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, true, "Reverting \"" + so.Name + "\" to prefab.");
+
+            PrefabUtility.RevertPrefab(so);
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Breaks a link between a prefab and its instance.
+        /// </summary>
+        [MenuItem("Scene Objects/Break prefab link", 8023)]
+        private static void BreakPrefabLink()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.BreakPrefab(so, "Breaking prefab link for " + so.Name);
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Cuts the currently selected scene object or resource.
+        /// </summary>
+        [MenuItem("Edit/Cut", 9450, true)]
+        public static void Cut()
+        {
+            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
+            {
+                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
+                if (win != null)
+                    win.CutSelection();
+            }
+            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
+            {
+                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+                if (win != null)
+                    win.CutSelection();
+            }
+        }
+
+        /// <summary>
+        /// Copies the currently selected scene object or resource.
+        /// </summary>
+        [MenuItem("Edit/Copy", 9449)]
+        public static void Copy()
+        {
+            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
+            {
+                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
+                if (win != null)
+                    win.CopySelection();
+            }
+            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
+            {
+                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+                if (win != null)
+                    win.CopySelection();
+            }
+        }
+
+        /// <summary>
+        /// Pastes the scene objects or resources that were previously cut or copied.
+        /// </summary>
+        [MenuItem("Edit/Paste", 9448)]
+        public static void Paste()
+        {
+            // TODO - This is slightly wrong in case both windows have something in their paste buffer (unify them?)
+
+            {
+                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
+                if (win != null)
+                    win.PasteToSelection();
+            }
+
+            {
+                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+                if (win != null)
+                    win.PasteToSelection();
+            }
+        }
+
+        /// <summary>
+        /// Deletes currently selected scene objects or resources.
+        /// </summary>
+        [MenuItem("Edit/Delete", 9447)]
+        public static void Delete()
+        {
+            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
+            {
+                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
+                if (win != null)
+                    win.DeleteSelection();
+            }
+            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
+            {
+                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+                if (win != null)
+                    win.DeleteSelection();
+            }
+        }
+
+        /// <summary>
+        /// Duplicates currently selected scene objects or resources.
+        /// </summary>
+        [MenuItem("Edit/Duplicate", 9446)]
+        public static void Duplicate()
+        {
+            if (Selection.SceneObjects != null && Selection.SceneObjects.Length > 0)
+            {
+                HierarchyWindow win = EditorWindow.GetWindow<HierarchyWindow>();
+                if (win != null)
+                    win.DuplicateSelection();
+            }
+            else if (Selection.ResourcePaths != null && Selection.ResourcePaths.Length > 0)
+            {
+                LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+                if (win != null)
+                    win.DuplicateSelection();
+            }
+        }
+    }
+}

+ 108 - 108
Source/MBansheeEngine/Component.cs

@@ -1,108 +1,108 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Base class for all components. Components represent primary logic elements in the scene. They are attached to 
-    /// scene objects.
-    ///
-    /// Implementations of <see cref="Component"/> can implement a set of callbacks that will be called by the runtime
-    /// at specified occassions:
-    /// void OnInitialize() - Called once when the component is instantiated. Only called when the game is playing.
-    /// void OnUpdate() - Called every frame while the game is running and the component is enabled.
-    /// void OnEnable() - Called whenever a component is enabled, or instantiated as enabled in which case it is called 
-    ///                   after OnInitialize. Only called when the game is playing or paused.
-    /// void OnDisable() - Called whenever a component is disabled. This includes destruction where it is called before 
-    ///                    OnDestroy. Only called when the game is playing or paused.
-    /// void OnDestroy() - Called before the component is destroyed. Destruction is usually delayed until the end of the 
-    ///                    current frame unless specified otherwise in a call to Destroy. 
-    /// void OnReset() - Called when script assemblies have been refreshed or when the component is initialized. During
-    ///                  initialization it is called after OnInitialize but before OnEnable. Only relevant in editor.
-    /// void OnTransformChanged(TransformChangedFlags) - Called when the transform of the owning scene object changes.
-    ///                                                  When and if this gets triggered depends on 
-    ///                                                  <see cref="NotifyFlags"/>.
-    ///
-    /// You can also make these callbacks trigger when the game is stopped/paused by using the <see cref="RunInEditor"/>
-    /// attribute on the component.
-    /// </summary>
-    public class Component : GameObject
-    {
-        // Internal use only
-        protected Component()
-        { }
-
-        /// <summary>
-        /// Returns the scene object this component is attached to.
-        /// </summary>
-        public SceneObject SceneObject
-        {
-            get { return Internal_GetSceneObject(mCachedPtr); }
-        }
-
-        /// <summary>
-        /// Determines in which situations will OnTransformChanged be triggered.
-        /// </summary>
-        protected TransformChangedFlags NotifyFlags
-        {
-            set { Internal_SetNotifyFlags(mCachedPtr, value); }
-            get { return Internal_GetNotifyFlags(mCachedPtr); }
-        }
-
-        /// <summary>
-        /// Destroys the component, removing it from its scene object and stopping component updates.
-        /// </summary>
-        /// <param name="immediate">If true the component will be fully destroyed immediately. This means that objects
-        ///                         that are still referencing this component might fail. Normally destruction is delayed
-        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
-        public void Destroy(bool immediate = false)
-        {
-            Internal_Destroy(mCachedPtr, immediate);
-        }
-
-        /// <summary>
-        /// Calculates bounds of the visible content for this component.
-        /// </summary>
-        /// <param name="box">Bounds in world space represented as an axis aligned bounding box.</param>
-        /// <param name="sphere">Bounds in world space represented as a sphere.</param>
-        /// <returns>True if the bounds have non-zero volume, false otherwise.</returns>
-        internal protected virtual bool CalculateBounds(out AABox box, out Sphere sphere)
-        {
-            Vector3 pos = SceneObject.Position;
-
-            box = new AABox(pos, pos);
-            sphere = new Sphere(pos, 0.0f);
-
-            return false;
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern Component Internal_AddComponent(SceneObject parent, Type type);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern Component Internal_GetComponent(SceneObject parent, Type type);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern Component[] Internal_GetComponents(SceneObject parent);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern Component[] Internal_GetComponentsPerType(SceneObject parent, Type type);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern Component Internal_RemoveComponent(SceneObject parent, Type type);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject Internal_GetSceneObject(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern TransformChangedFlags Internal_GetNotifyFlags(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_SetNotifyFlags(IntPtr nativeInstance, TransformChangedFlags flags);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Base class for all components. Components represent primary logic elements in the scene. They are attached to 
+    /// scene objects.
+    ///
+    /// Implementations of <see cref="Component"/> can implement a set of callbacks that will be called by the runtime
+    /// at specified occassions:
+    /// void OnInitialize() - Called once when the component is instantiated. Only called when the game is playing.
+    /// void OnUpdate() - Called every frame while the game is running and the component is enabled.
+    /// void OnEnable() - Called whenever a component is enabled, or instantiated as enabled in which case it is called 
+    ///                   after OnInitialize. Only called when the game is playing.
+    /// void OnDisable() - Called whenever a component is disabled. This includes destruction where it is called before 
+    ///                    OnDestroy. Only called when the game is playing.
+    /// void OnDestroy() - Called before the component is destroyed. Destruction is usually delayed until the end of the 
+    ///                    current frame unless specified otherwise in a call to Destroy. 
+    /// void OnReset() - Called when script assemblies have been refreshed or when the component is initialized. During
+    ///                  initialization it is called after OnInitialize but before OnEnable. Only relevant in editor.
+    /// void OnTransformChanged(TransformChangedFlags) - Called when the transform of the owning scene object changes.
+    ///                                                  When and if this gets triggered depends on 
+    ///                                                  <see cref="NotifyFlags"/>.
+    ///
+    /// You can also make these callbacks trigger when the game is stopped/paused by using the <see cref="RunInEditor"/>
+    /// attribute on the component.
+    /// </summary>
+    public class Component : GameObject
+    {
+        // Internal use only
+        protected Component()
+        { }
+
+        /// <summary>
+        /// Returns the scene object this component is attached to.
+        /// </summary>
+        public SceneObject SceneObject
+        {
+            get { return Internal_GetSceneObject(mCachedPtr); }
+        }
+
+        /// <summary>
+        /// Determines in which situations will OnTransformChanged be triggered.
+        /// </summary>
+        protected TransformChangedFlags NotifyFlags
+        {
+            set { Internal_SetNotifyFlags(mCachedPtr, value); }
+            get { return Internal_GetNotifyFlags(mCachedPtr); }
+        }
+
+        /// <summary>
+        /// Destroys the component, removing it from its scene object and stopping component updates.
+        /// </summary>
+        /// <param name="immediate">If true the component will be fully destroyed immediately. This means that objects
+        ///                         that are still referencing this component might fail. Normally destruction is delayed
+        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
+        public void Destroy(bool immediate = false)
+        {
+            Internal_Destroy(mCachedPtr, immediate);
+        }
+
+        /// <summary>
+        /// Calculates bounds of the visible content for this component.
+        /// </summary>
+        /// <param name="box">Bounds in world space represented as an axis aligned bounding box.</param>
+        /// <param name="sphere">Bounds in world space represented as a sphere.</param>
+        /// <returns>True if the bounds have non-zero volume, false otherwise.</returns>
+        internal protected virtual bool CalculateBounds(out AABox box, out Sphere sphere)
+        {
+            Vector3 pos = SceneObject.Position;
+
+            box = new AABox(pos, pos);
+            sphere = new Sphere(pos, 0.0f);
+
+            return false;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component Internal_AddComponent(SceneObject parent, Type type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component Internal_GetComponent(SceneObject parent, Type type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component[] Internal_GetComponents(SceneObject parent);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component[] Internal_GetComponentsPerType(SceneObject parent, Type type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component Internal_RemoveComponent(SceneObject parent, Type type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern SceneObject Internal_GetSceneObject(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern TransformChangedFlags Internal_GetNotifyFlags(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_SetNotifyFlags(IntPtr nativeInstance, TransformChangedFlags flags);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
+    }
+}

+ 799 - 799
Source/MBansheeEngine/Math/Quaternion.cs

@@ -1,799 +1,799 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Quaternion used for representing rotations.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential), SerializeObject]
-    public struct Quaternion // Note: Must match C++ class Quaternion
-    {
-        /// <summary>
-        /// Contains constant data that is used when calculating euler angles in a certain order.
-        /// </summary>
-        private struct EulerAngleOrderData
-		{
-            public EulerAngleOrderData(int a, int b, int c)
-            {
-                this.a = a;
-                this.b = b;
-                this.c = c;
-            }
-
-			public int a, b, c;
-		};
-
-        /// <summary>
-        /// Quaternion with all zero elements.
-        /// </summary>
-        public static readonly Quaternion Zero = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);
-
-        /// <summary>
-        /// Quaternion representing no rotation.
-        /// </summary>
-        public static readonly Quaternion Identity = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
-
-        private static readonly float epsilon = 1e-03f;
-
-        private static readonly EulerAngleOrderData[] EA_LOOKUP = new EulerAngleOrderData[6]
-		    { new EulerAngleOrderData(0, 1, 2), new EulerAngleOrderData(0, 2, 1), new EulerAngleOrderData(1, 0, 2),
-		      new EulerAngleOrderData(1, 2, 0), new EulerAngleOrderData(2, 0, 1), new EulerAngleOrderData(2, 1, 0) };
-
-        public float x;
-        public float y;
-        public float z;
-        public float w;
-
-        /// <summary>
-        /// Accesses a specific component of the quaternion.
-        /// </summary>
-        /// <param name="index">Index of the component (0 - x, 1 - y, 2 - z, 3 - w).</param>
-        /// <returns>Value of the specific component.</returns>
-        public float this[int index]
-        {
-            get
-            {
-                switch (index)
-                {
-                    case 0:
-                        return x;
-                    case 1:
-                        return y;
-                    case 2:
-                        return z;
-                    case 3:
-                        return w;
-                    default:
-                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
-                }
-            }
-            set
-            {
-                switch (index)
-                {
-                    case 0:
-                        x = value;
-                        break;
-                    case 1:
-                        y = value;
-                        break;
-                    case 2:
-                        z = value;
-                        break;
-                    case 3:
-                        w = value;
-                        break;
-                    default:
-                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets the positive x-axis of the coordinate system transformed by this quaternion.
-        /// </summary>
-        public Vector3 Right
-        {
-            get
-            {
-                float fTy = 2.0f*y;
-                float fTz = 2.0f*z;
-                float fTwy = fTy*w;
-                float fTwz = fTz*w;
-                float fTxy = fTy*x;
-                float fTxz = fTz*x;
-                float fTyy = fTy*y;
-                float fTzz = fTz*z;
-
-                return new Vector3(1.0f - (fTyy + fTzz), fTxy + fTwz, fTxz - fTwy);
-            }
-        }
-
-        /// <summary>
-        /// Gets the positive y-axis of the coordinate system transformed by this quaternion.
-        /// </summary>
-        public Vector3 Up
-        {
-            get
-            {
-                float fTx = 2.0f * x;
-                float fTy = 2.0f * y;
-                float fTz = 2.0f * z;
-                float fTwx = fTx * w;
-                float fTwz = fTz * w;
-                float fTxx = fTx * x;
-                float fTxy = fTy * x;
-                float fTyz = fTz * y;
-                float fTzz = fTz * z;
-
-                return new Vector3(fTxy - fTwz, 1.0f - (fTxx + fTzz), fTyz + fTwx);
-            }
-        }
-
-        /// <summary>
-        /// Gets the positive z-axis of the coordinate system transformed by this quaternion.
-        /// </summary>
-        public Vector3 Forward
-        {
-            get
-            {
-                float fTx = 2.0f * x;
-                float fTy = 2.0f * y;
-                float fTz = 2.0f * z;
-                float fTwx = fTx * w;
-                float fTwy = fTy * w;
-                float fTxx = fTx * x;
-                float fTxz = fTz * x;
-                float fTyy = fTy * y;
-                float fTyz = fTz * y;
-
-                return new Vector3(fTxz + fTwy, fTyz - fTwx, 1.0f - (fTxx + fTyy));
-            }
-        }
-
-        /// <summary>
-        /// Returns the inverse of the quaternion. Quaternion must be non-zero. Inverse quaternion has the opposite
-        /// rotation of the original.
-        /// </summary>
-        public Quaternion Inverse
-        {
-            get
-            {
-                Quaternion copy = this;
-                copy.Invert();
-                return copy;
-            }
-        }
-
-        /// <summary>
-        /// Returns a normalized copy of the quaternion.
-        /// </summary>
-        public Quaternion Normalized
-        {
-            get
-            {
-                Quaternion copy = this;
-                copy.Normalize();
-                return copy;
-            }
-        }
-
-        /// <summary>
-        /// Constructs a new quaternion with the specified components.
-        /// </summary>
-        public Quaternion(float x, float y, float z, float w)
-        {
-            this.x = x;
-            this.y = y;
-            this.z = z;
-            this.w = w;
-        }
-
-        public static Quaternion operator* (Quaternion lhs, Quaternion rhs)
-        {
-            return new Quaternion((lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y), 
-                (lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z), 
-                (lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x), 
-                (lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z));
-        }
-
-        public static Quaternion operator* (float lhs, Quaternion rhs)
-        {
-            return new Quaternion(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
-        }
-
-        public static Quaternion operator+ (Quaternion lhs, Quaternion rhs)
-        {
-            return new Quaternion(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
-        }
-
-        public static Quaternion operator- (Quaternion lhs, Quaternion rhs)
-        {
-            return new Quaternion(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
-        }
-
-        public static Quaternion operator- (Quaternion quat)
-        {
-            return new Quaternion(-quat.x, -quat.y, -quat.z, -quat.w);
-        }
-
-        public static bool operator== (Quaternion lhs, Quaternion rhs)
-        {
-            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
-        }
-
-        public static bool operator!= (Quaternion lhs, Quaternion rhs)
-        {
-            return !(lhs == rhs);
-        }
-
-        /// <summary>
-        /// Calculates a dot product between two quaternions.
-        /// </summary>
-        /// <param name="a">First quaternion.</param>
-        /// <param name="b">Second quaternion.</param>
-        /// <returns>Dot product between the two quaternions.</returns>
-        public static float Dot(Quaternion a, Quaternion b)
-        {
-            return (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
-        }
-
-        /// <summary>
-        /// Applies quaternion rotation to the specified point.
-        /// </summary>
-        /// <param name="point">Point to rotate.</param>
-        /// <returns>Point rotated by the quaternion.</returns>
-        public Vector3 Rotate(Vector3 point)
-        {
-            return ToRotationMatrix().Transform(point);
-        }
-
-        /// <summary>
-        /// Initializes the quaternion with rotation that rotates from one direction to another.
-        /// </summary>
-        /// <param name="fromDirection">Rotation to start at.</param>
-        /// <param name="toDirection">Rotation to end at.</param>
-        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
-        {
-            SetFromToRotation(fromDirection, toDirection, Vector3.Zero);
-        }
-
-        /// <summary>
-        /// Initializes the quaternion with rotation that rotates from one direction to another.
-        /// </summary>
-        /// <param name="fromDirection">Rotation to start at.</param>
-        /// <param name="toDirection">Rotation to end at.</param>
-        /// <param name="fallbackAxis">Fallback axis to use if the from/to vectors are almost completely opposite.
-        ///                            Fallback axis should be perpendicular to both vectors.</param>
-        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
-        {
-		    fromDirection.Normalize();
-		    toDirection.Normalize();
-
-		    float d = Vector3.Dot(fromDirection, toDirection);
-
-		    // If dot == 1, vectors are the same
-            if (d >= 1.0f)
-            {
-                this = Identity;
-                return;
-            }
-
-            if (d < (1e-6f - 1.0f))
-		    {
-			    if (fallbackAxis != Vector3.Zero)
-			    {
-				    // Rotate 180 degrees about the fallback axis
-				    this = FromAxisAngle(fallbackAxis, MathEx.Pi * MathEx.Rad2Deg);
-			    }
-			    else
-			    {
-				    // Generate an axis
-				    Vector3 axis = Vector3.Cross(Vector3.XAxis, fromDirection);
-                    if (axis.SqrdLength < ((1e-06f * 1e-06f))) // Pick another if collinear
-					    axis = Vector3.Cross(Vector3.YAxis, fromDirection);
-				    axis.Normalize();
-                    this = FromAxisAngle(axis, MathEx.Pi * MathEx.Rad2Deg);
-			    }
-		    }
-		    else
-		    {
-			    float s = MathEx.Sqrt((1+d)*2);
-			    float invs = 1 / s;
-
-			    Vector3 c = Vector3.Cross(fromDirection, toDirection);
-
-			    x = c.x * invs;
-			    y = c.y * invs;
-			    z = c.z * invs;
-			    w = s * 0.5f;
-			    Normalize();
-		    }
-        }
-
-        /// <summary>
-        /// Normalizes the quaternion.
-        /// </summary>
-        /// <returns>Length of the quaternion prior to normalization.</returns>
-        public float Normalize()
-        {
-            float len = w*w+x*x+y*y+z*z;
-            float factor = 1.0f / (float)MathEx.Sqrt(len);
-
-            x *= factor;
-            y *= factor;
-            z *= factor;
-            w *= factor;
-            return len;
-        }
-
-        /// <summary>
-        /// Calculates the inverse of the quaternion. Inverse quaternion has the opposite rotation of the original.
-        /// </summary>
-        public void Invert()
-        {
-            float fNorm = w * w + x * x + y * y + z * z;
-            if (fNorm > 0.0f)
-            {
-                float fInvNorm = 1.0f / fNorm;
-                x *= -fInvNorm;
-                y *= -fInvNorm;
-                z *= -fInvNorm;
-                w *= fInvNorm;
-            }
-            else
-            {
-                this = Zero;
-            }
-        }
-
-        /// <summary>
-        /// Initializes the quaternion so that it orients an object so it faces in te provided direction.
-        /// </summary>
-        /// <param name="forward">Direction to orient the object towards.</param>
-        public void SetLookRotation(Vector3 forward)
-        {
-            FromToRotation(-Vector3.ZAxis, forward);
-        }
-
-        /// <summary>
-        /// Initializes the quaternion so that it orients an object so it faces in te provided direction.
-        /// </summary>
-        /// <param name="forward">Direction to orient the object towards.</param>
-        /// <param name="up">Axis that determines the upward direction of the object.</param>
-        public void SetLookRotation(Vector3 forward, Vector3 up)
-        {
-            Vector3 forwardNrm = Vector3.Normalize(forward);
-            Vector3 upNrm = Vector3.Normalize(up);
-
-            if (MathEx.ApproxEquals(Vector3.Dot(forwardNrm, upNrm), 1.0f))
-            {
-                SetLookRotation(forwardNrm);
-                return;
-            }
-
-            Vector3 x = Vector3.Cross(forwardNrm, upNrm);
-            Vector3 y = Vector3.Cross(x, forwardNrm);
-
-            x.Normalize();
-            y.Normalize();
-
-            this = Quaternion.FromAxes(x, y, -forwardNrm);
-        }
-
-        /// <summary>
-        /// Performs spherical interpolation between two quaternions. Spherical interpolation neatly interpolates between
-        /// two rotations without modifying the size of the vector it is applied to (unlike linear interpolation).
-        /// </summary>
-        /// <param name="from">Start quaternion.</param>
-        /// <param name="to">End quaternion.</param>
-        /// <param name="t">Interpolation factor in range [0, 1] that determines how much to interpolate between
-        /// <paramref name="from"/> and <paramref name="to"/>.</param>
-        /// <param name="shortestPath">Should the interpolation be performed between the shortest or longest path between
-        ///                            the two quaternions.</param>
-        /// <returns>Interpolated quaternion representing a rotation between <paramref name="from"/> and 
-        /// <paramref name="to"/>.</returns>
-        public static Quaternion Slerp(Quaternion from, Quaternion to, float t, bool shortestPath = true)
-        {
-            float dot = Dot(from, to);
-            Quaternion quat;
-
-            if (dot < 0.0f && shortestPath)
-            {
-                dot = -dot;
-                quat = -to;
-            }
-            else
-            {
-                quat = to;
-            }
-
-            if (MathEx.Abs(dot) < (1 - epsilon))
-            {
-                float sin = MathEx.Sqrt(1 - (dot*dot));
-                Radian angle = MathEx.Atan2(sin, dot);
-                float invSin = 1.0f / sin;
-                float a = MathEx.Sin((1.0f - t) * angle) * invSin;
-                float b = MathEx.Sin(t * angle) * invSin;
-
-                return a * from + b * quat;
-            }
-            else
-            {
-                Quaternion ret = (1.0f - t) * from + t * quat;
-
-                ret.Normalize();
-                return ret;
-            }
-        }
-
-        /// <summary>
-        /// Returns the inverse of the quaternion. Quaternion must be non-zero. Inverse quaternion has the opposite
-        /// rotation of the original.
-        /// </summary>
-        /// <param name="rotation">Quaternion to calculate the inverse for.</param>
-        /// <returns>Inverse of the provided quaternion.</returns>
-        public static Quaternion Invert(Quaternion rotation)
-        {
-            Quaternion copy = rotation;
-            copy.Invert();
-
-            return copy;
-        }
-
-        /// <summary>
-        /// Calculates an angle between two rotations.
-        /// </summary>
-        /// <param name="a">First rotation.</param>
-        /// <param name="b">Second rotation.</param>
-        /// <returns>Angle between the rotations, in degrees.</returns>
-        public static Degree Angle(Quaternion a, Quaternion b)
-        {
-            return (MathEx.Acos(MathEx.Min(MathEx.Abs(Dot(a, b)), 1.0f)) * 2.0f * MathEx.Rad2Deg);
-        }
-
-        /// <summary>
-        /// Converts the quaternion rotation into axis/angle rotation.
-        /// </summary>
-        /// <param name="axis">Axis around which the rotation is performed.</param>
-        /// <param name="angle">Amount of rotation.</param>
-        public void ToAxisAngle(out Vector3 axis, out Degree angle)
-        {
-            float fSqrLength = x*x+y*y+z*z;
-		    if (fSqrLength > 0.0f)
-		    {
-                angle = 2.0f * MathEx.Acos(w) * MathEx.Rad2Deg;
-			    float fInvLength = MathEx.InvSqrt(fSqrLength);
-			    axis.x = x*fInvLength;
-			    axis.y = y*fInvLength;
-			    axis.z = z*fInvLength;
-		    }
-		    else
-		    {
-			    // Angle is 0, so any axis will do
-                angle = (Degree)0.0f;
-			    axis.x = 1.0f;
-			    axis.y = 0.0f;
-			    axis.z = 0.0f;
-		    }
-        }
-
-        /// <summary>
-        /// Converts a quaternion into an orthonormal set of axes.
-        /// </summary>
-        /// <param name="xAxis">Output normalized x axis.</param>
-        /// <param name="yAxis">Output normalized y axis.</param>
-        /// <param name="zAxis">Output normalized z axis.</param>
-        public void ToAxes(ref Vector3 xAxis, ref Vector3 yAxis, ref Vector3 zAxis)
-        {
-            Matrix3 matRot = ToRotationMatrix();
-
-            xAxis.x = matRot[0, 0];
-		    xAxis.y = matRot[1, 0];
-		    xAxis.z = matRot[2, 0];
-
-		    yAxis.x = matRot[0, 1];
-		    yAxis.y = matRot[1, 1];
-		    yAxis.z = matRot[2, 1];
-
-		    zAxis.x = matRot[0, 2];
-		    zAxis.y = matRot[1, 2];
-		    zAxis.z = matRot[2, 2];
-	    }
-
-    /// <summary>
-    /// Converts the quaternion rotation into euler angle (pitch/yaw/roll) rotation.
-    /// </summary>
-    /// <returns>Rotation as euler angles, in degrees.</returns>
-    public Vector3 ToEuler()
-        {
-            Matrix3 matRot = ToRotationMatrix();
-            return matRot.ToEulerAngles();
-        }
-
-        /// <summary>
-        /// Converts a quaternion rotation into a rotation matrix.
-        /// </summary>
-        /// <returns>Matrix representing the rotation.</returns>
-        public Matrix3 ToRotationMatrix()
-        {
-            Matrix3 mat = new Matrix3();
-
-            float tx = x + x;
-            float ty = y + y;
-            float fTz = z + z;
-            float twx = tx * w;
-            float twy = ty * w;
-            float twz = fTz * w;
-            float txx = tx * x;
-            float txy = ty * x;
-            float txz = fTz * x;
-            float tyy = ty * y;
-            float tyz = fTz * y;
-            float tzz = fTz * z;
-
-            mat[0, 0] = 1.0f - (tyy + tzz);
-            mat[0, 1] = txy - twz;
-            mat[0, 2] = txz + twy;
-            mat[1, 0] = txy + twz;
-            mat[1, 1] = 1.0f - (txx + tzz);
-            mat[1, 2] = tyz - twx;
-            mat[2, 0] = txz - twy;
-            mat[2, 1] = tyz + twx;
-            mat[2, 2] = 1.0f - (txx + tyy);
-
-            return mat;
-        }
-
-        /// <summary>
-        /// Creates a quaternion with rotation that rotates from one direction to another.
-        /// </summary>
-        /// <param name="fromDirection">Rotation to start at.</param>
-        /// <param name="toDirection">Rotation to end at.</param>
-        /// <returns>Quaternion that rotates an object from <paramref name="fromDirection"/> to 
-        /// <paramref name="toDirection"/></returns>
-        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection)
-        {
-            Quaternion q = new Quaternion();
-            q.SetFromToRotation(fromDirection, toDirection);
-            return q;
-        }
-
-        /// <summary>
-        /// Creates a quaternion with rotation that rotates from one direction to another.
-        /// </summary>
-        /// <param name="fromDirection">Rotation to start at.</param>
-        /// <param name="toDirection">Rotation to end at.</param>
-        /// <param name="fallbackAxis">Fallback axis to use if the from/to vectors are almost completely opposite.
-        ///                            Fallback axis should be perpendicular to both vectors.</param>
-        /// <returns>Quaternion that rotates an object from <paramref name="fromDirection"/> to 
-        /// <paramref name="toDirection"/></returns>
-        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
-        {
-            Quaternion q = new Quaternion();
-            q.SetFromToRotation(fromDirection, toDirection, fallbackAxis);
-            return q;
-        }
-
-        /// <summary>
-        /// Creates a quaternion that orients an object so it faces in te provided direction.
-        /// </summary>
-        /// <param name="forward">Direction to orient the object towards.</param>
-        public static Quaternion LookRotation(Vector3 forward)
-        {
-            Quaternion quat = new Quaternion();
-            quat.SetLookRotation(forward);
-
-            return quat;
-        }
-
-        /// <summary>
-        /// Creates a quaternion that orients an object so it faces in te provided direction.
-        /// </summary>
-        /// <param name="forward">Direction to orient the object towards.</param>
-        /// <param name="up">Axis that determines the upward direction of the object.</param>
-        public static Quaternion LookRotation(Vector3 forward, Vector3 up)
-        {
-            Quaternion quat = new Quaternion();
-            quat.SetLookRotation(forward, up);
-
-            return quat;
-        }
-
-        /// <summary>
-        /// Converts the quaternion rotation into euler angle (pitch/yaw/roll) rotation.
-        /// </summary>
-        /// <param name="rotation">Quaternion to convert.</param>
-        /// <returns>Rotation as euler angles, in degrees.</returns>
-        public static Vector3 ToEuler(Quaternion rotation)
-        {
-            return rotation.ToEuler();
-        }
-
-        /// <summary>
-        /// Converts the quaternion rotation into axis/angle rotation.
-        /// </summary>
-        /// <param name="rotation">Quaternion to convert.</param>
-        /// <param name="axis">Axis around which the rotation is performed.</param>
-        /// <param name="angle">Amount of rotation.</param>
-        public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angle)
-        {
-            rotation.ToAxisAngle(out axis, out angle);
-        }
-
-        /// <summary>
-        /// Creates a quaternion from a rotation matrix.
-        /// </summary>
-        /// <param name="rotMatrix">Rotation matrix to convert to quaternion.</param>
-        /// <returns>Newly created quaternion that has equivalent rotation as the provided rotation matrix.</returns>
-        public static Quaternion FromRotationMatrix(Matrix3 rotMatrix)
-        {
-            // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
-            // article "Quaternion Calculus and Fast Animation".
-
-            Quaternion quat = new Quaternion();
-            float trace = rotMatrix.m00 + rotMatrix.m11 + rotMatrix.m22;
-            float root;
-
-            if (trace > 0.0f)
-            {
-                // |w| > 1/2, may as well choose w > 1/2
-                root = MathEx.Sqrt(trace + 1.0f);  // 2w
-                quat.w = 0.5f*root;
-                root = 0.5f/root;  // 1/(4w)
-                quat.x = (rotMatrix.m21 - rotMatrix.m12) * root;
-                quat.y = (rotMatrix.m02 - rotMatrix.m20) * root;
-                quat.z = (rotMatrix.m10 - rotMatrix.m01) * root;
-            }
-            else
-            {
-                // |w| <= 1/2
-                int[] nextLookup = { 1, 2, 0 };
-                int i = 0;
-
-                if (rotMatrix.m11 > rotMatrix.m00)
-                    i = 1;
-
-                if (rotMatrix.m22 > rotMatrix[i, i])
-                    i = 2;
-
-                int j = nextLookup[i];
-                int k = nextLookup[j];
-
-                root = MathEx.Sqrt(rotMatrix[i,i] - rotMatrix[j, j] - rotMatrix[k, k] + 1.0f);
-
-                quat[i] = 0.5f*root;
-                root = 0.5f/root;
-
-                quat.w = (rotMatrix[k, j] - rotMatrix[j, k]) * root;
-                quat[j] = (rotMatrix[j, i] + rotMatrix[i, j]) * root;
-                quat[k] = (rotMatrix[k, i] + rotMatrix[i, k]) * root;
-            }
-
-		    quat.Normalize();
-
-            return quat;
-        }
-
-        /// <summary>
-        /// Creates a quaternion from axis/angle rotation.
-        /// </summary>
-        /// <param name="axis">Axis around which the rotation is performed.</param>
-        /// <param name="angle">Amount of rotation.</param>
-        /// <returns>Quaternion that rotates an object around the specified axis for the specified amount.</returns>
-        public static Quaternion FromAxisAngle(Vector3 axis, Degree angle)
-        {
-            Quaternion quat;
-
-            float halfAngle = (float)(0.5f*angle.Radians);
-            float sin = (float)MathEx.Sin(halfAngle);
-            quat.w = (float)MathEx.Cos(halfAngle);
-            quat.x = sin * axis.x;
-            quat.y = sin * axis.y;
-            quat.z = sin * axis.z;
-
-            return quat;
-        }
-
-        /// <summary>
-        /// Initializes the quaternion from orthonormal set of axes. 
-        /// </summary>
-        /// <param name="xAxis">Normalized x axis.</param>
-        /// <param name="yAxis">Normalized y axis.</param>
-        /// <param name="zAxis">Normalized z axis.</param>
-        /// <returns>Quaternion that represents a rotation from base axes to the specified set of axes.</returns>
-        public static Quaternion FromAxes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
-        {
-            Matrix3 mat;
-
-            mat.m00 = xAxis.x;
-            mat.m10 = xAxis.y;
-            mat.m20 = xAxis.z;
-
-            mat.m01 = yAxis.x;
-            mat.m11 = yAxis.y;
-            mat.m21 = yAxis.z;
-
-            mat.m02 = zAxis.x;
-            mat.m12 = zAxis.y;
-            mat.m22 = zAxis.z;
-
-            return FromRotationMatrix(mat);
-        }
-
-        /// <summary>
-        /// Creates a quaternion from the provided euler angle (pitch/yaw/roll) rotation.
-        /// </summary>
-        /// <param name="xAngle">Pitch angle of rotation.</param>
-        /// <param name="yAngle">Yar angle of rotation.</param>
-        /// <param name="zAngle">Roll angle of rotation.</param>
-        /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
-        ///                     on the order.</param>
-        /// <returns>Quaternion that can rotate an object to the specified angles.</returns>
-        public static Quaternion FromEuler(Degree xAngle, Degree yAngle, Degree zAngle, 
-            EulerAngleOrder order = EulerAngleOrder.YXZ)
-        {
-		    EulerAngleOrderData l = EA_LOOKUP[(int)order];
-
-		    Radian halfXAngle = xAngle * 0.5f;
-		    Radian halfYAngle = yAngle * 0.5f;
-		    Radian halfZAngle = zAngle * 0.5f;
-
-		    float cx = MathEx.Cos(halfXAngle);
-		    float sx = MathEx.Sin(halfXAngle);
-
-		    float cy = MathEx.Cos(halfYAngle);
-		    float sy = MathEx.Sin(halfYAngle);
-
-		    float cz = MathEx.Cos(halfZAngle);
-		    float sz = MathEx.Sin(halfZAngle);
-
-		    Quaternion[] quats = new Quaternion[3];
-		    quats[0] = new Quaternion(sx, 0.0f, 0.0f, cx);
-		    quats[1] = new Quaternion(0.0f, sy, 0.0f, cy);
-		    quats[2] = new Quaternion(0.0f, 0.0f, sz, cz);
-
-		    return (quats[l.a] * quats[l.b]) * quats[l.c];
-        }
-
-        /// <summary>
-        /// Creates a quaternion from the provided euler angle (pitch/yaw/roll) rotation.
-        /// </summary>
-        /// <param name="euler">Euler angles in degrees.</param>
-        /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
-        ///                     on the order.</param>
-        /// <returns>Quaternion that can rotate an object to the specified angles.</returns>
-        public static Quaternion FromEuler(Vector3 euler, EulerAngleOrder order = EulerAngleOrder.YXZ)
-        {
-            return FromEuler((Degree)euler.x, (Degree)euler.y, (Degree)euler.z, order);
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return x.GetHashCode() ^ y.GetHashCode() << 2 ^ z.GetHashCode() >> 2 ^ w.GetHashCode() >> 1;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object other)
-        {
-            if (!(other is Quaternion))
-                return false;
-
-            Quaternion quat = (Quaternion)other;
-            if (x.Equals(quat.x) && y.Equals(quat.y) && z.Equals(quat.z) && w.Equals(quat.w))
-                return true;
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override string ToString()
-        {
-            return String.Format("({0}, {1}, {2}, {3})", x, y, z, w);
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Quaternion used for representing rotations.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential), SerializeObject]
+    public struct Quaternion // Note: Must match C++ class Quaternion
+    {
+        /// <summary>
+        /// Contains constant data that is used when calculating euler angles in a certain order.
+        /// </summary>
+        private struct EulerAngleOrderData
+		{
+            public EulerAngleOrderData(int a, int b, int c)
+            {
+                this.a = a;
+                this.b = b;
+                this.c = c;
+            }
+
+			public int a, b, c;
+		};
+
+        /// <summary>
+        /// Quaternion with all zero elements.
+        /// </summary>
+        public static readonly Quaternion Zero = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);
+
+        /// <summary>
+        /// Quaternion representing no rotation.
+        /// </summary>
+        public static readonly Quaternion Identity = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
+
+        private static readonly float epsilon = 1e-03f;
+
+        private static readonly EulerAngleOrderData[] EA_LOOKUP = new EulerAngleOrderData[6]
+		    { new EulerAngleOrderData(0, 1, 2), new EulerAngleOrderData(0, 2, 1), new EulerAngleOrderData(1, 0, 2),
+		      new EulerAngleOrderData(1, 2, 0), new EulerAngleOrderData(2, 0, 1), new EulerAngleOrderData(2, 1, 0) };
+
+        public float x;
+        public float y;
+        public float z;
+        public float w;
+
+        /// <summary>
+        /// Accesses a specific component of the quaternion.
+        /// </summary>
+        /// <param name="index">Index of the component (0 - x, 1 - y, 2 - z, 3 - w).</param>
+        /// <returns>Value of the specific component.</returns>
+        public float this[int index]
+        {
+            get
+            {
+                switch (index)
+                {
+                    case 0:
+                        return x;
+                    case 1:
+                        return y;
+                    case 2:
+                        return z;
+                    case 3:
+                        return w;
+                    default:
+                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
+                }
+            }
+            set
+            {
+                switch (index)
+                {
+                    case 0:
+                        x = value;
+                        break;
+                    case 1:
+                        y = value;
+                        break;
+                    case 2:
+                        z = value;
+                        break;
+                    case 3:
+                        w = value;
+                        break;
+                    default:
+                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the positive x-axis of the coordinate system transformed by this quaternion.
+        /// </summary>
+        public Vector3 Right
+        {
+            get
+            {
+                float fTy = 2.0f*y;
+                float fTz = 2.0f*z;
+                float fTwy = fTy*w;
+                float fTwz = fTz*w;
+                float fTxy = fTy*x;
+                float fTxz = fTz*x;
+                float fTyy = fTy*y;
+                float fTzz = fTz*z;
+
+                return new Vector3(1.0f - (fTyy + fTzz), fTxy + fTwz, fTxz - fTwy);
+            }
+        }
+
+        /// <summary>
+        /// Gets the positive y-axis of the coordinate system transformed by this quaternion.
+        /// </summary>
+        public Vector3 Up
+        {
+            get
+            {
+                float fTx = 2.0f * x;
+                float fTy = 2.0f * y;
+                float fTz = 2.0f * z;
+                float fTwx = fTx * w;
+                float fTwz = fTz * w;
+                float fTxx = fTx * x;
+                float fTxy = fTy * x;
+                float fTyz = fTz * y;
+                float fTzz = fTz * z;
+
+                return new Vector3(fTxy - fTwz, 1.0f - (fTxx + fTzz), fTyz + fTwx);
+            }
+        }
+
+        /// <summary>
+        /// Gets the positive z-axis of the coordinate system transformed by this quaternion.
+        /// </summary>
+        public Vector3 Forward
+        {
+            get
+            {
+                float fTx = 2.0f * x;
+                float fTy = 2.0f * y;
+                float fTz = 2.0f * z;
+                float fTwx = fTx * w;
+                float fTwy = fTy * w;
+                float fTxx = fTx * x;
+                float fTxz = fTz * x;
+                float fTyy = fTy * y;
+                float fTyz = fTz * y;
+
+                return new Vector3(fTxz + fTwy, fTyz - fTwx, 1.0f - (fTxx + fTyy));
+            }
+        }
+
+        /// <summary>
+        /// Returns the inverse of the quaternion. Quaternion must be non-zero. Inverse quaternion has the opposite
+        /// rotation of the original.
+        /// </summary>
+        public Quaternion Inverse
+        {
+            get
+            {
+                Quaternion copy = this;
+                copy.Invert();
+                return copy;
+            }
+        }
+
+        /// <summary>
+        /// Returns a normalized copy of the quaternion.
+        /// </summary>
+        public Quaternion Normalized
+        {
+            get
+            {
+                Quaternion copy = this;
+                copy.Normalize();
+                return copy;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new quaternion with the specified components.
+        /// </summary>
+        public Quaternion(float x, float y, float z, float w)
+        {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+
+        public static Quaternion operator* (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion((lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y), 
+                (lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z), 
+                (lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x), 
+                (lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z));
+        }
+
+        public static Quaternion operator* (float lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
+        }
+
+        public static Quaternion operator+ (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
+        }
+
+        public static Quaternion operator- (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
+        }
+
+        public static Quaternion operator- (Quaternion quat)
+        {
+            return new Quaternion(-quat.x, -quat.y, -quat.z, -quat.w);
+        }
+
+        public static bool operator== (Quaternion lhs, Quaternion rhs)
+        {
+            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
+        }
+
+        public static bool operator!= (Quaternion lhs, Quaternion rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        /// <summary>
+        /// Calculates a dot product between two quaternions.
+        /// </summary>
+        /// <param name="a">First quaternion.</param>
+        /// <param name="b">Second quaternion.</param>
+        /// <returns>Dot product between the two quaternions.</returns>
+        public static float Dot(Quaternion a, Quaternion b)
+        {
+            return (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
+        }
+
+        /// <summary>
+        /// Applies quaternion rotation to the specified point.
+        /// </summary>
+        /// <param name="point">Point to rotate.</param>
+        /// <returns>Point rotated by the quaternion.</returns>
+        public Vector3 Rotate(Vector3 point)
+        {
+            return ToRotationMatrix().Transform(point);
+        }
+
+        /// <summary>
+        /// Initializes the quaternion with rotation that rotates from one direction to another.
+        /// </summary>
+        /// <param name="fromDirection">Rotation to start at.</param>
+        /// <param name="toDirection">Rotation to end at.</param>
+        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
+        {
+            SetFromToRotation(fromDirection, toDirection, Vector3.Zero);
+        }
+
+        /// <summary>
+        /// Initializes the quaternion with rotation that rotates from one direction to another.
+        /// </summary>
+        /// <param name="fromDirection">Rotation to start at.</param>
+        /// <param name="toDirection">Rotation to end at.</param>
+        /// <param name="fallbackAxis">Fallback axis to use if the from/to vectors are almost completely opposite.
+        ///                            Fallback axis should be perpendicular to both vectors.</param>
+        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
+        {
+		    fromDirection.Normalize();
+		    toDirection.Normalize();
+
+		    float d = Vector3.Dot(fromDirection, toDirection);
+
+		    // If dot == 1, vectors are the same
+            if (d >= 1.0f)
+            {
+                this = Identity;
+                return;
+            }
+
+            if (d < (1e-6f - 1.0f))
+		    {
+			    if (fallbackAxis != Vector3.Zero)
+			    {
+				    // Rotate 180 degrees about the fallback axis
+				    this = FromAxisAngle(fallbackAxis, MathEx.Pi * MathEx.Rad2Deg);
+			    }
+			    else
+			    {
+				    // Generate an axis
+				    Vector3 axis = Vector3.Cross(Vector3.XAxis, fromDirection);
+                    if (axis.SqrdLength < ((1e-06f * 1e-06f))) // Pick another if collinear
+					    axis = Vector3.Cross(Vector3.YAxis, fromDirection);
+				    axis.Normalize();
+                    this = FromAxisAngle(axis, MathEx.Pi * MathEx.Rad2Deg);
+			    }
+		    }
+		    else
+		    {
+			    float s = MathEx.Sqrt((1+d)*2);
+			    float invs = 1 / s;
+
+			    Vector3 c = Vector3.Cross(fromDirection, toDirection);
+
+			    x = c.x * invs;
+			    y = c.y * invs;
+			    z = c.z * invs;
+			    w = s * 0.5f;
+			    Normalize();
+		    }
+        }
+
+        /// <summary>
+        /// Normalizes the quaternion.
+        /// </summary>
+        /// <returns>Length of the quaternion prior to normalization.</returns>
+        public float Normalize()
+        {
+            float len = w*w+x*x+y*y+z*z;
+            float factor = 1.0f / (float)MathEx.Sqrt(len);
+
+            x *= factor;
+            y *= factor;
+            z *= factor;
+            w *= factor;
+            return len;
+        }
+
+        /// <summary>
+        /// Calculates the inverse of the quaternion. Inverse quaternion has the opposite rotation of the original.
+        /// </summary>
+        public void Invert()
+        {
+            float fNorm = w * w + x * x + y * y + z * z;
+            if (fNorm > 0.0f)
+            {
+                float fInvNorm = 1.0f / fNorm;
+                x *= -fInvNorm;
+                y *= -fInvNorm;
+                z *= -fInvNorm;
+                w *= fInvNorm;
+            }
+            else
+            {
+                this = Zero;
+            }
+        }
+
+        /// <summary>
+        /// Initializes the quaternion so that it orients an object so it faces in te provided direction.
+        /// </summary>
+        /// <param name="forward">Direction to orient the object towards.</param>
+        public void SetLookRotation(Vector3 forward)
+        {
+            FromToRotation(-Vector3.ZAxis, forward);
+        }
+
+        /// <summary>
+        /// Initializes the quaternion so that it orients an object so it faces in te provided direction.
+        /// </summary>
+        /// <param name="forward">Direction to orient the object towards.</param>
+        /// <param name="up">Axis that determines the upward direction of the object.</param>
+        public void SetLookRotation(Vector3 forward, Vector3 up)
+        {
+            Vector3 forwardNrm = Vector3.Normalize(forward);
+            Vector3 upNrm = Vector3.Normalize(up);
+
+            if (MathEx.ApproxEquals(Vector3.Dot(forwardNrm, upNrm), 1.0f))
+            {
+                SetLookRotation(forwardNrm);
+                return;
+            }
+
+            Vector3 x = Vector3.Cross(forwardNrm, upNrm);
+            Vector3 y = Vector3.Cross(x, forwardNrm);
+
+            x.Normalize();
+            y.Normalize();
+
+            this = Quaternion.FromAxes(x, y, -forwardNrm);
+        }
+
+        /// <summary>
+        /// Performs spherical interpolation between two quaternions. Spherical interpolation neatly interpolates between
+        /// two rotations without modifying the size of the vector it is applied to (unlike linear interpolation).
+        /// </summary>
+        /// <param name="from">Start quaternion.</param>
+        /// <param name="to">End quaternion.</param>
+        /// <param name="t">Interpolation factor in range [0, 1] that determines how much to interpolate between
+        /// <paramref name="from"/> and <paramref name="to"/>.</param>
+        /// <param name="shortestPath">Should the interpolation be performed between the shortest or longest path between
+        ///                            the two quaternions.</param>
+        /// <returns>Interpolated quaternion representing a rotation between <paramref name="from"/> and 
+        /// <paramref name="to"/>.</returns>
+        public static Quaternion Slerp(Quaternion from, Quaternion to, float t, bool shortestPath = true)
+        {
+            float dot = Dot(from, to);
+            Quaternion quat;
+
+            if (dot < 0.0f && shortestPath)
+            {
+                dot = -dot;
+                quat = -to;
+            }
+            else
+            {
+                quat = to;
+            }
+
+            if (MathEx.Abs(dot) < (1 - epsilon))
+            {
+                float sin = MathEx.Sqrt(1 - (dot*dot));
+                Radian angle = MathEx.Atan2(sin, dot);
+                float invSin = 1.0f / sin;
+                float a = MathEx.Sin((1.0f - t) * angle) * invSin;
+                float b = MathEx.Sin(t * angle) * invSin;
+
+                return a * from + b * quat;
+            }
+            else
+            {
+                Quaternion ret = (1.0f - t) * from + t * quat;
+
+                ret.Normalize();
+                return ret;
+            }
+        }
+
+        /// <summary>
+        /// Returns the inverse of the quaternion. Quaternion must be non-zero. Inverse quaternion has the opposite
+        /// rotation of the original.
+        /// </summary>
+        /// <param name="rotation">Quaternion to calculate the inverse for.</param>
+        /// <returns>Inverse of the provided quaternion.</returns>
+        public static Quaternion Invert(Quaternion rotation)
+        {
+            Quaternion copy = rotation;
+            copy.Invert();
+
+            return copy;
+        }
+
+        /// <summary>
+        /// Calculates an angle between two rotations.
+        /// </summary>
+        /// <param name="a">First rotation.</param>
+        /// <param name="b">Second rotation.</param>
+        /// <returns>Angle between the rotations, in degrees.</returns>
+        public static Degree Angle(Quaternion a, Quaternion b)
+        {
+            return (MathEx.Acos(MathEx.Min(MathEx.Abs(Dot(a, b)), 1.0f)) * 2.0f * MathEx.Rad2Deg);
+        }
+
+        /// <summary>
+        /// Converts the quaternion rotation into axis/angle rotation.
+        /// </summary>
+        /// <param name="axis">Axis around which the rotation is performed.</param>
+        /// <param name="angle">Amount of rotation.</param>
+        public void ToAxisAngle(out Vector3 axis, out Degree angle)
+        {
+            float fSqrLength = x*x+y*y+z*z;
+		    if (fSqrLength > 0.0f)
+		    {
+                angle = 2.0f * MathEx.Acos(w) * MathEx.Rad2Deg;
+			    float fInvLength = MathEx.InvSqrt(fSqrLength);
+			    axis.x = x*fInvLength;
+			    axis.y = y*fInvLength;
+			    axis.z = z*fInvLength;
+		    }
+		    else
+		    {
+			    // Angle is 0, so any axis will do
+                angle = (Degree)0.0f;
+			    axis.x = 1.0f;
+			    axis.y = 0.0f;
+			    axis.z = 0.0f;
+		    }
+        }
+
+        /// <summary>
+        /// Converts a quaternion into an orthonormal set of axes.
+        /// </summary>
+        /// <param name="xAxis">Output normalized x axis.</param>
+        /// <param name="yAxis">Output normalized y axis.</param>
+        /// <param name="zAxis">Output normalized z axis.</param>
+        public void ToAxes(ref Vector3 xAxis, ref Vector3 yAxis, ref Vector3 zAxis)
+        {
+            Matrix3 matRot = ToRotationMatrix();
+
+            xAxis.x = matRot[0, 0];
+		    xAxis.y = matRot[1, 0];
+		    xAxis.z = matRot[2, 0];
+
+		    yAxis.x = matRot[0, 1];
+		    yAxis.y = matRot[1, 1];
+		    yAxis.z = matRot[2, 1];
+
+		    zAxis.x = matRot[0, 2];
+		    zAxis.y = matRot[1, 2];
+		    zAxis.z = matRot[2, 2];
+	    }
+
+    /// <summary>
+    /// Converts the quaternion rotation into euler angle (pitch/yaw/roll) rotation.
+    /// </summary>
+    /// <returns>Rotation as euler angles, in degrees.</returns>
+    public Vector3 ToEuler()
+        {
+            Matrix3 matRot = ToRotationMatrix();
+            return matRot.ToEulerAngles();
+        }
+
+        /// <summary>
+        /// Converts a quaternion rotation into a rotation matrix.
+        /// </summary>
+        /// <returns>Matrix representing the rotation.</returns>
+        public Matrix3 ToRotationMatrix()
+        {
+            Matrix3 mat = new Matrix3();
+
+            float tx = x + x;
+            float ty = y + y;
+            float fTz = z + z;
+            float twx = tx * w;
+            float twy = ty * w;
+            float twz = fTz * w;
+            float txx = tx * x;
+            float txy = ty * x;
+            float txz = fTz * x;
+            float tyy = ty * y;
+            float tyz = fTz * y;
+            float tzz = fTz * z;
+
+            mat[0, 0] = 1.0f - (tyy + tzz);
+            mat[0, 1] = txy - twz;
+            mat[0, 2] = txz + twy;
+            mat[1, 0] = txy + twz;
+            mat[1, 1] = 1.0f - (txx + tzz);
+            mat[1, 2] = tyz - twx;
+            mat[2, 0] = txz - twy;
+            mat[2, 1] = tyz + twx;
+            mat[2, 2] = 1.0f - (txx + tyy);
+
+            return mat;
+        }
+
+        /// <summary>
+        /// Creates a quaternion with rotation that rotates from one direction to another.
+        /// </summary>
+        /// <param name="fromDirection">Rotation to start at.</param>
+        /// <param name="toDirection">Rotation to end at.</param>
+        /// <returns>Quaternion that rotates an object from <paramref name="fromDirection"/> to 
+        /// <paramref name="toDirection"/></returns>
+        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection)
+        {
+            Quaternion q = new Quaternion();
+            q.SetFromToRotation(fromDirection, toDirection);
+            return q;
+        }
+
+        /// <summary>
+        /// Creates a quaternion with rotation that rotates from one direction to another.
+        /// </summary>
+        /// <param name="fromDirection">Rotation to start at.</param>
+        /// <param name="toDirection">Rotation to end at.</param>
+        /// <param name="fallbackAxis">Fallback axis to use if the from/to vectors are almost completely opposite.
+        ///                            Fallback axis should be perpendicular to both vectors.</param>
+        /// <returns>Quaternion that rotates an object from <paramref name="fromDirection"/> to 
+        /// <paramref name="toDirection"/></returns>
+        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
+        {
+            Quaternion q = new Quaternion();
+            q.SetFromToRotation(fromDirection, toDirection, fallbackAxis);
+            return q;
+        }
+
+        /// <summary>
+        /// Creates a quaternion that orients an object so it faces in te provided direction.
+        /// </summary>
+        /// <param name="forward">Direction to orient the object towards.</param>
+        public static Quaternion LookRotation(Vector3 forward)
+        {
+            Quaternion quat = new Quaternion();
+            quat.SetLookRotation(forward);
+
+            return quat;
+        }
+
+        /// <summary>
+        /// Creates a quaternion that orients an object so it faces in te provided direction.
+        /// </summary>
+        /// <param name="forward">Direction to orient the object towards.</param>
+        /// <param name="up">Axis that determines the upward direction of the object.</param>
+        public static Quaternion LookRotation(Vector3 forward, Vector3 up)
+        {
+            Quaternion quat = new Quaternion();
+            quat.SetLookRotation(forward, up);
+
+            return quat;
+        }
+
+        /// <summary>
+        /// Converts the quaternion rotation into euler angle (pitch/yaw/roll) rotation.
+        /// </summary>
+        /// <param name="rotation">Quaternion to convert.</param>
+        /// <returns>Rotation as euler angles, in degrees.</returns>
+        public static Vector3 ToEuler(Quaternion rotation)
+        {
+            return rotation.ToEuler();
+        }
+
+        /// <summary>
+        /// Converts the quaternion rotation into axis/angle rotation.
+        /// </summary>
+        /// <param name="rotation">Quaternion to convert.</param>
+        /// <param name="axis">Axis around which the rotation is performed.</param>
+        /// <param name="angle">Amount of rotation.</param>
+        public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angle)
+        {
+            rotation.ToAxisAngle(out axis, out angle);
+        }
+
+        /// <summary>
+        /// Creates a quaternion from a rotation matrix.
+        /// </summary>
+        /// <param name="rotMatrix">Rotation matrix to convert to quaternion.</param>
+        /// <returns>Newly created quaternion that has equivalent rotation as the provided rotation matrix.</returns>
+        public static Quaternion FromRotationMatrix(Matrix3 rotMatrix)
+        {
+            // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+            // article "Quaternion Calculus and Fast Animation".
+
+            Quaternion quat = new Quaternion();
+            float trace = rotMatrix.m00 + rotMatrix.m11 + rotMatrix.m22;
+            float root;
+
+            if (trace > 0.0f)
+            {
+                // |w| > 1/2, may as well choose w > 1/2
+                root = MathEx.Sqrt(trace + 1.0f);  // 2w
+                quat.w = 0.5f*root;
+                root = 0.5f/root;  // 1/(4w)
+                quat.x = (rotMatrix.m21 - rotMatrix.m12) * root;
+                quat.y = (rotMatrix.m02 - rotMatrix.m20) * root;
+                quat.z = (rotMatrix.m10 - rotMatrix.m01) * root;
+            }
+            else
+            {
+                // |w| <= 1/2
+                int[] nextLookup = { 1, 2, 0 };
+                int i = 0;
+
+                if (rotMatrix.m11 > rotMatrix.m00)
+                    i = 1;
+
+                if (rotMatrix.m22 > rotMatrix[i, i])
+                    i = 2;
+
+                int j = nextLookup[i];
+                int k = nextLookup[j];
+
+                root = MathEx.Sqrt(rotMatrix[i,i] - rotMatrix[j, j] - rotMatrix[k, k] + 1.0f);
+
+                quat[i] = 0.5f*root;
+                root = 0.5f/root;
+
+                quat.w = (rotMatrix[k, j] - rotMatrix[j, k]) * root;
+                quat[j] = (rotMatrix[j, i] + rotMatrix[i, j]) * root;
+                quat[k] = (rotMatrix[k, i] + rotMatrix[i, k]) * root;
+            }
+
+		    quat.Normalize();
+
+            return quat;
+        }
+
+        /// <summary>
+        /// Creates a quaternion from axis/angle rotation.
+        /// </summary>
+        /// <param name="axis">Axis around which the rotation is performed.</param>
+        /// <param name="angle">Amount of rotation.</param>
+        /// <returns>Quaternion that rotates an object around the specified axis for the specified amount.</returns>
+        public static Quaternion FromAxisAngle(Vector3 axis, Degree angle)
+        {
+            Quaternion quat;
+
+            float halfAngle = (float)(0.5f*angle.Radians);
+            float sin = (float)MathEx.Sin(halfAngle);
+            quat.w = (float)MathEx.Cos(halfAngle);
+            quat.x = sin * axis.x;
+            quat.y = sin * axis.y;
+            quat.z = sin * axis.z;
+
+            return quat;
+        }
+
+        /// <summary>
+        /// Initializes the quaternion from orthonormal set of axes. 
+        /// </summary>
+        /// <param name="xAxis">Normalized x axis.</param>
+        /// <param name="yAxis">Normalized y axis.</param>
+        /// <param name="zAxis">Normalized z axis.</param>
+        /// <returns>Quaternion that represents a rotation from base axes to the specified set of axes.</returns>
+        public static Quaternion FromAxes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+        {
+            Matrix3 mat;
+
+            mat.m00 = xAxis.x;
+            mat.m10 = xAxis.y;
+            mat.m20 = xAxis.z;
+
+            mat.m01 = yAxis.x;
+            mat.m11 = yAxis.y;
+            mat.m21 = yAxis.z;
+
+            mat.m02 = zAxis.x;
+            mat.m12 = zAxis.y;
+            mat.m22 = zAxis.z;
+
+            return FromRotationMatrix(mat);
+        }
+
+        /// <summary>
+        /// Creates a quaternion from the provided euler angle (pitch/yaw/roll) rotation.
+        /// </summary>
+        /// <param name="xAngle">Pitch angle of rotation.</param>
+        /// <param name="yAngle">Yar angle of rotation.</param>
+        /// <param name="zAngle">Roll angle of rotation.</param>
+        /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
+        ///                     on the order.</param>
+        /// <returns>Quaternion that can rotate an object to the specified angles.</returns>
+        public static Quaternion FromEuler(Degree xAngle, Degree yAngle, Degree zAngle, 
+            EulerAngleOrder order = EulerAngleOrder.YXZ)
+        {
+		    EulerAngleOrderData l = EA_LOOKUP[(int)order];
+
+		    Radian halfXAngle = xAngle * 0.5f;
+		    Radian halfYAngle = yAngle * 0.5f;
+		    Radian halfZAngle = zAngle * 0.5f;
+
+		    float cx = MathEx.Cos(halfXAngle);
+		    float sx = MathEx.Sin(halfXAngle);
+
+		    float cy = MathEx.Cos(halfYAngle);
+		    float sy = MathEx.Sin(halfYAngle);
+
+		    float cz = MathEx.Cos(halfZAngle);
+		    float sz = MathEx.Sin(halfZAngle);
+
+		    Quaternion[] quats = new Quaternion[3];
+		    quats[0] = new Quaternion(sx, 0.0f, 0.0f, cx);
+		    quats[1] = new Quaternion(0.0f, sy, 0.0f, cy);
+		    quats[2] = new Quaternion(0.0f, 0.0f, sz, cz);
+
+		    return (quats[l.a] * quats[l.b]) * quats[l.c];
+        }
+
+        /// <summary>
+        /// Creates a quaternion from the provided euler angle (pitch/yaw/roll) rotation.
+        /// </summary>
+        /// <param name="euler">Euler angles in degrees.</param>
+        /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
+        ///                     on the order.</param>
+        /// <returns>Quaternion that can rotate an object to the specified angles.</returns>
+        public static Quaternion FromEuler(Vector3 euler, EulerAngleOrder order = EulerAngleOrder.YXZ)
+        {
+            return FromEuler((Degree)euler.x, (Degree)euler.y, (Degree)euler.z, order);
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ y.GetHashCode() << 2 ^ z.GetHashCode() >> 2 ^ w.GetHashCode() >> 1;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object other)
+        {
+            if (!(other is Quaternion))
+                return false;
+
+            Quaternion quat = (Quaternion)other;
+            if (x.Equals(quat.x) && y.Equals(quat.y) && z.Equals(quat.z) && w.Equals(quat.w))
+                return true;
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override string ToString()
+        {
+            return String.Format("({0}, {1}, {2}, {3})", x, y, z, w);
+        }
+    }
+}

+ 15 - 8
Source/MBansheeEngine/Physics/Collider.cs

@@ -104,13 +104,16 @@ namespace BansheeEngine
         /// Determines how far apart do two shapes need to be away from each other before the physics runtime starts 
         /// generating repelling impulse for them.This distance will be the sum of contact offsets of the two interacting
         /// objects.If objects are moving fast you can increase this value to start generating the impulse earlier and 
-        /// potentially prevent the objects from interpenetrating. This value is in meters.
+        /// potentially prevent the objects from interpenetrating. This value is in meters. Must be positive and larger
+        /// than <see cref="RestOffset"/>.
         /// </summary>
         public float ContactOffset
         {
             get { return serializableData.contactOffset; }
             set
             {
+                value = MathEx.Max(0, MathEx.Max(value, RestOffset));
+
                 serializableData.contactOffset = value;
 
                 if (native != null)
@@ -120,13 +123,16 @@ namespace BansheeEngine
 
         /// <summary>
         /// Determines at what distance should two objects resting on one another come to an equilibrium. The value used in the
-        /// runtime will be the sum of rest offsets for both interacting objects. This value is in meters.
+        /// runtime will be the sum of rest offsets for both interacting objects. This value is in meters. Cannot be larger
+        /// than <see cref="ContactOffset"/>
         /// </summary>
         public float RestOffset
         {
             get { return serializableData.restOffset; }
             set
             {
+                value = MathEx.Min(value, ContactOffset);
+
                 serializableData.restOffset = value;
 
                 if (native != null)
@@ -373,7 +379,8 @@ namespace BansheeEngine
             if (parent != null)
                 mode = parent.CollisionReportMode;
 
-            native.CollisionReportMode = mode;
+            if(native != null)
+                native.CollisionReportMode = mode;
         }
 
         private void OnInitialize()
@@ -464,13 +471,13 @@ namespace BansheeEngine
         [SerializeObject]
         internal class SerializableData
         {
-            public Vector3 localPosition;
-            public Quaternion localRotation;
-            public bool isTrigger;
+            public Vector3 localPosition = Vector3.Zero;
+            public Quaternion localRotation = Quaternion.Identity;
+            public bool isTrigger = false;
             public float mass = 1.0f;
             public PhysicsMaterial material;
-            public float contactOffset;
-            public float restOffset;
+            public float contactOffset = 0.02f;
+            public float restOffset = 0.0f;
             public ulong layer = 1;
             public CollisionReportMode collisionReportMode = CollisionReportMode.None;
         }

+ 300 - 300
Source/MBansheeEngine/Physics/D6Joint.cs

@@ -1,300 +1,300 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Represents the most customizable type of joint. This joint type can be used to create all other built-in joint 
-    /// types, and to design your own custom ones, but is less intuitive to use.Allows a specification of a linear
-    /// constraint (e.g. for slider), twist constraint(rotating around X) and swing constraint(rotating around Y and Z).
-    /// It also allows you to constrain limits to only specific axes or completely lock specific axes.
-    /// </summary>
-    public sealed class D6Joint : Joint
-    {
-        [SerializeField]
-        private LimitLinear linearLimit = new LimitLinear();
-        [SerializeField]
-        private LimitAngularRange twistLimit = new LimitAngularRange();
-        [SerializeField]
-        private LimitConeRange swingLimit = new LimitConeRange();
-        [SerializeField]
-        private D6JointMotion[] motion = new D6JointMotion[(int)D6JointAxis.Count];
-        [SerializeField]
-        private D6JointDrive[] drives = new D6JointDrive[(int)D6JointDriveType.Count];
-        [SerializeField]
-        private Vector3 drivePosition;
-        [SerializeField]
-        private Quaternion driveRotation;
-        [SerializeField]
-        private Vector3 driveLinearVelocity;
-        [SerializeField]
-        private Vector3 driveAngularVelocity;
-
-        /// <summary>
-        /// Returns the current rotation of the joint around the X axis.
-        /// </summary>
-        public Radian Twist
-        {
-            get
-            {
-                if (Native != null)
-                    return Native.Twist;
-
-                return new Radian(0.0f);
-            }
-        }
-
-        /// <summary>
-        /// Returns the current rotation of the joint around the Y axis.
-        /// </summary>
-        public Radian SwingY
-        {
-            get
-            {
-                if (Native != null)
-                    return Native.SwingY;
-
-                return new Radian(0.0f);
-            }
-        }
-
-        /// <summary>
-        /// Returns the current rotation of the joint around the Z axis.
-        /// </summary>
-        public Radian SwingZ
-        {
-            get
-            {
-                if (Native != null)
-                    return Native.SwingZ;
-
-                return new Radian(0.0f);
-            }
-        }
-
-        /// <summary>
-        /// Linear limit used for constraining translation degrees of freedom.
-        /// </summary>
-        public LimitLinear LimitLinear
-        {
-            get { return linearLimit; }
-            set
-            {
-                if (linearLimit == value)
-                    return;
-
-                linearLimit = value;
-
-                if (Native != null)
-                    Native.LimitLinear = value;
-            }
-        }
-
-        /// <summary>
-        /// Angular limit used for constraining the twist (rotation around X) degree of freedom.
-        /// </summary>
-        public LimitAngularRange LimitTwist
-        {
-            get { return twistLimit; }
-            set
-            {
-                if (twistLimit == value)
-                    return;
-
-                twistLimit = value;
-
-                if (Native != null)
-                    Native.LimitTwist = value;
-            }
-        }
-
-        /// <summary>
-        /// Cone limit used for constraining the swing (rotation around Y and Z) degree of freedom.
-        /// </summary>
-        public LimitConeRange LimitSwing
-        {
-            get { return swingLimit; }
-            set
-            {
-                if (swingLimit == value)
-                    return;
-
-                swingLimit = value;
-
-                if (Native != null)
-                    Native.LimitSwing = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines the drive's target position relative to the joint's first body. This is the position the drive will
-        /// attempt to reach if enabled.
-        /// </summary>
-        public Vector3 DrivePosition
-        {
-            get { return drivePosition; }
-            set
-            {
-                if (drivePosition == value)
-                    return;
-
-                drivePosition = value;
-
-                if (Native != null)
-                    Native.DrivePosition = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines the drive's target orientation relative to the joint's first body. This is the orientation the drive
-        /// will attempt to reach if enabled.
-        /// </summary>
-        public Quaternion DriveRotation
-        {
-            get { return driveRotation; }
-            set
-            {
-                if (driveRotation == value)
-                    return;
-
-                driveRotation = value;
-
-                if (Native != null)
-                    Native.DriveRotation = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines the drive's target linear velocity. This is the velocity the drive will attempt to reach if enabled.
-        /// </summary>
-        public Vector3 DriveLinearVelocity
-        {
-            get { return driveLinearVelocity; }
-            set
-            {
-                if (driveLinearVelocity == value)
-                    return;
-
-                driveLinearVelocity = value;
-
-                if (Native != null)
-                    Native.DriveLinearVelocity = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines the drive's target angular velocity. This is the velocity the drive will attempt to reach if enabled.
-        /// </summary>
-        public Vector3 DriveAngularVelocity
-        {
-            get { return driveAngularVelocity; }
-            set
-            {
-                if (driveAngularVelocity == value)
-                    return;
-
-                driveAngularVelocity = value;
-
-                if (Native != null)
-                    Native.DriveAngularVelocity = value;
-            }
-        }
-
-        /// <summary>
-        /// Returns the type of motion constrain for the specified axis.
-        /// </summary>
-        /// <param name="axis">Axis to retrieve the motion constrain for.</param>
-        /// <returns>Motion constrain type for the axis.</returns>
-        public D6JointMotion GetMotion(D6JointAxis axis)
-        {
-            return motion[(int) axis];
-        }
-
-        /// <summary>
-        /// Allows you to constrain motion of the specified axis. Be aware that when setting drives for a specific axis
-        ///  you must also take care not to constrain its motion in a conflicting way(e.g.you cannot add a drive that
-        /// moves the joint on X axis, and then lock the X axis).
-        /// 
-        /// Unlocking translations degrees of freedom allows the bodies to move along the subset of the unlocked axes.
-        /// (e.g.unlocking just one translational axis is the equivalent of a slider joint.)
-        /// 
-        /// Angular degrees of freedom are partitioned as twist(around X axis) and swing(around Y and Z axes). Different
-        /// effects can be achieves by unlocking their various combinations: 
-        ///  - If a single degree of angular freedom is unlocked it should be the twist degree as it has extra options for
-        ///    that case (e.g. for a hinge joint).
-        ///  - If both swing degrees are unlocked but twist is locked the result is a zero-twist joint.
-        ///  - If one swing and one twist degree of freedom are unlocked the result is a zero-swing joint (e.g.an arm
-        ///    attached at the elbow)
-        ///  - If all angular degrees of freedom are unlocked the result is the same as the spherical joint.
-        /// </summary>
-        /// <param name="axis">Axis to change the motion type for.</param>
-        /// <param name="motion">Type of motion for the axis.</param>
-        public void SetMotion(D6JointAxis axis, D6JointMotion motion)
-        {
-            if (this.motion[(int)axis] == motion)
-                return;
-
-            this.motion[(int)axis] = motion;
-
-            if (Native != null)
-                Native.SetMotion(axis, motion);
-        }
-
-        /// <summary>
-        /// Returns properties for the specified drive type.
-        /// </summary>
-        /// <param name="type">Type of drive to retrieve properties for.</param>
-        /// <returns>Properties for the requested drive type.</returns>
-        public D6JointDrive GetDrive(D6JointDriveType type)
-        {
-            return drives[(int) type];
-        }
-
-        /// <summary>
-        /// Sets a drive that will attempt to move the specified degree(s) of freedom to the wanted position and velocity. 
-        /// </summary>
-        /// <param name="type">Type of the drive.</param>
-        /// <param name="drive">Drive properties.</param>
-        public void SetDrive(D6JointDriveType type, D6JointDrive drive)
-        {
-            if (this.drives[(int)type] == drive)
-                return;
-
-            this.drives[(int)type] = drive;
-
-            if (Native != null)
-                Native.SetDrive(type, drive);
-        }
-
-        /// <summary>
-        /// Returns the native joint wrapped by this component.
-        /// </summary>
-        private NativeD6Joint Native
-        {
-            get { return (NativeD6Joint)native; }
-        }
-
-        /// <inheritdoc/>
-        internal override NativeJoint CreateNative()
-        {
-            NativeD6Joint joint = new NativeD6Joint();
-
-            // TODO - Apply this all at once to avoid all the individual interop function calls
-            joint.LimitLinear = linearLimit;
-            joint.LimitTwist = twistLimit;
-            joint.LimitSwing = swingLimit;
-
-            for (int i = 0; i < (int) D6JointAxis.Count; i++)
-                joint.SetMotion((D6JointAxis) i, motion[i]);
-
-            for (int i = 0; i < (int)D6JointDriveType.Count; i++)
-                joint.SetDrive((D6JointDriveType)i, drives[i]);
-
-            joint.DrivePosition = drivePosition;
-            joint.DriveRotation = driveRotation;
-            joint.DriveLinearVelocity = driveLinearVelocity;
-            joint.DriveAngularVelocity = driveAngularVelocity;
-
-            return joint;
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Represents the most customizable type of joint. This joint type can be used to create all other built-in joint 
+    /// types, and to design your own custom ones, but is less intuitive to use.Allows a specification of a linear
+    /// constraint (e.g. for slider), twist constraint(rotating around X) and swing constraint(rotating around Y and Z).
+    /// It also allows you to constrain limits to only specific axes or completely lock specific axes.
+    /// </summary>
+    public sealed class D6Joint : Joint
+    {
+        [SerializeField]
+        private LimitLinear linearLimit = new LimitLinear();
+        [SerializeField]
+        private LimitAngularRange twistLimit = new LimitAngularRange();
+        [SerializeField]
+        private LimitConeRange swingLimit = new LimitConeRange();
+        [SerializeField]
+        private D6JointMotion[] motion = new D6JointMotion[(int)D6JointAxis.Count];
+        [SerializeField]
+        private D6JointDrive[] drives = new D6JointDrive[(int)D6JointDriveType.Count];
+        [SerializeField]
+        private Vector3 drivePosition = Vector3.Zero;
+        [SerializeField]
+        private Quaternion driveRotation = Quaternion.Identity;
+        [SerializeField]
+        private Vector3 driveLinearVelocity = Vector3.Zero;
+        [SerializeField]
+        private Vector3 driveAngularVelocity = Vector3.Zero;
+
+        /// <summary>
+        /// Returns the current rotation of the joint around the X axis.
+        /// </summary>
+        public Radian Twist
+        {
+            get
+            {
+                if (Native != null)
+                    return Native.Twist;
+
+                return new Radian(0.0f);
+            }
+        }
+
+        /// <summary>
+        /// Returns the current rotation of the joint around the Y axis.
+        /// </summary>
+        public Radian SwingY
+        {
+            get
+            {
+                if (Native != null)
+                    return Native.SwingY;
+
+                return new Radian(0.0f);
+            }
+        }
+
+        /// <summary>
+        /// Returns the current rotation of the joint around the Z axis.
+        /// </summary>
+        public Radian SwingZ
+        {
+            get
+            {
+                if (Native != null)
+                    return Native.SwingZ;
+
+                return new Radian(0.0f);
+            }
+        }
+
+        /// <summary>
+        /// Linear limit used for constraining translation degrees of freedom.
+        /// </summary>
+        public LimitLinear LimitLinear
+        {
+            get { return linearLimit; }
+            set
+            {
+                if (linearLimit == value)
+                    return;
+
+                linearLimit = value;
+
+                if (Native != null)
+                    Native.LimitLinear = value;
+            }
+        }
+
+        /// <summary>
+        /// Angular limit used for constraining the twist (rotation around X) degree of freedom.
+        /// </summary>
+        public LimitAngularRange LimitTwist
+        {
+            get { return twistLimit; }
+            set
+            {
+                if (twistLimit == value)
+                    return;
+
+                twistLimit = value;
+
+                if (Native != null)
+                    Native.LimitTwist = value;
+            }
+        }
+
+        /// <summary>
+        /// Cone limit used for constraining the swing (rotation around Y and Z) degree of freedom.
+        /// </summary>
+        public LimitConeRange LimitSwing
+        {
+            get { return swingLimit; }
+            set
+            {
+                if (swingLimit == value)
+                    return;
+
+                swingLimit = value;
+
+                if (Native != null)
+                    Native.LimitSwing = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines the drive's target position relative to the joint's first body. This is the position the drive will
+        /// attempt to reach if enabled.
+        /// </summary>
+        public Vector3 DrivePosition
+        {
+            get { return drivePosition; }
+            set
+            {
+                if (drivePosition == value)
+                    return;
+
+                drivePosition = value;
+
+                if (Native != null)
+                    Native.DrivePosition = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines the drive's target orientation relative to the joint's first body. This is the orientation the drive
+        /// will attempt to reach if enabled.
+        /// </summary>
+        public Quaternion DriveRotation
+        {
+            get { return driveRotation; }
+            set
+            {
+                if (driveRotation == value)
+                    return;
+
+                driveRotation = value;
+
+                if (Native != null)
+                    Native.DriveRotation = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines the drive's target linear velocity. This is the velocity the drive will attempt to reach if enabled.
+        /// </summary>
+        public Vector3 DriveLinearVelocity
+        {
+            get { return driveLinearVelocity; }
+            set
+            {
+                if (driveLinearVelocity == value)
+                    return;
+
+                driveLinearVelocity = value;
+
+                if (Native != null)
+                    Native.DriveLinearVelocity = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines the drive's target angular velocity. This is the velocity the drive will attempt to reach if enabled.
+        /// </summary>
+        public Vector3 DriveAngularVelocity
+        {
+            get { return driveAngularVelocity; }
+            set
+            {
+                if (driveAngularVelocity == value)
+                    return;
+
+                driveAngularVelocity = value;
+
+                if (Native != null)
+                    Native.DriveAngularVelocity = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns the type of motion constrain for the specified axis.
+        /// </summary>
+        /// <param name="axis">Axis to retrieve the motion constrain for.</param>
+        /// <returns>Motion constrain type for the axis.</returns>
+        public D6JointMotion GetMotion(D6JointAxis axis)
+        {
+            return motion[(int) axis];
+        }
+
+        /// <summary>
+        /// Allows you to constrain motion of the specified axis. Be aware that when setting drives for a specific axis
+        ///  you must also take care not to constrain its motion in a conflicting way(e.g.you cannot add a drive that
+        /// moves the joint on X axis, and then lock the X axis).
+        /// 
+        /// Unlocking translations degrees of freedom allows the bodies to move along the subset of the unlocked axes.
+        /// (e.g.unlocking just one translational axis is the equivalent of a slider joint.)
+        /// 
+        /// Angular degrees of freedom are partitioned as twist(around X axis) and swing(around Y and Z axes). Different
+        /// effects can be achieves by unlocking their various combinations: 
+        ///  - If a single degree of angular freedom is unlocked it should be the twist degree as it has extra options for
+        ///    that case (e.g. for a hinge joint).
+        ///  - If both swing degrees are unlocked but twist is locked the result is a zero-twist joint.
+        ///  - If one swing and one twist degree of freedom are unlocked the result is a zero-swing joint (e.g.an arm
+        ///    attached at the elbow)
+        ///  - If all angular degrees of freedom are unlocked the result is the same as the spherical joint.
+        /// </summary>
+        /// <param name="axis">Axis to change the motion type for.</param>
+        /// <param name="motion">Type of motion for the axis.</param>
+        public void SetMotion(D6JointAxis axis, D6JointMotion motion)
+        {
+            if (this.motion[(int)axis] == motion)
+                return;
+
+            this.motion[(int)axis] = motion;
+
+            if (Native != null)
+                Native.SetMotion(axis, motion);
+        }
+
+        /// <summary>
+        /// Returns properties for the specified drive type.
+        /// </summary>
+        /// <param name="type">Type of drive to retrieve properties for.</param>
+        /// <returns>Properties for the requested drive type.</returns>
+        public D6JointDrive GetDrive(D6JointDriveType type)
+        {
+            return drives[(int) type];
+        }
+
+        /// <summary>
+        /// Sets a drive that will attempt to move the specified degree(s) of freedom to the wanted position and velocity. 
+        /// </summary>
+        /// <param name="type">Type of the drive.</param>
+        /// <param name="drive">Drive properties.</param>
+        public void SetDrive(D6JointDriveType type, D6JointDrive drive)
+        {
+            if (this.drives[(int)type] == drive)
+                return;
+
+            this.drives[(int)type] = drive;
+
+            if (Native != null)
+                Native.SetDrive(type, drive);
+        }
+
+        /// <summary>
+        /// Returns the native joint wrapped by this component.
+        /// </summary>
+        private NativeD6Joint Native
+        {
+            get { return (NativeD6Joint)native; }
+        }
+
+        /// <inheritdoc/>
+        internal override NativeJoint CreateNative()
+        {
+            NativeD6Joint joint = new NativeD6Joint();
+
+            // TODO - Apply this all at once to avoid all the individual interop function calls
+            joint.LimitLinear = linearLimit;
+            joint.LimitTwist = twistLimit;
+            joint.LimitSwing = swingLimit;
+
+            for (int i = 0; i < (int) D6JointAxis.Count; i++)
+                joint.SetMotion((D6JointAxis) i, motion[i]);
+
+            for (int i = 0; i < (int)D6JointDriveType.Count; i++)
+                joint.SetDrive((D6JointDriveType)i, drives[i]);
+
+            joint.DrivePosition = drivePosition;
+            joint.DriveRotation = driveRotation;
+            joint.DriveLinearVelocity = driveLinearVelocity;
+            joint.DriveAngularVelocity = driveAngularVelocity;
+
+            return joint;
+        }
+    }
+}

+ 802 - 802
Source/MBansheeEngine/Physics/Rigidbody.cs

@@ -1,802 +1,802 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Collections.Generic;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Rigidbody is a dynamic physics object that can be moved using forces (or directly). It will interact with other
-    /// static and dynamic physics objects in the scene accordingly(i.e.it will push other non-kinematic rigidbodies,
-    /// and collide with static objects).
-    /// 
-    /// The shape and mass of a rigidbody is governed by its colliders. You must attach at least one collider for the
-    /// rigidbody to be valid. Colliders that are on the same scene object as the rigidbody, or on child scene objects
-    /// are automatically considered as part of the rigidbody.
-    /// </summary>
-    public sealed class Rigidbody : Component
-    {
-        internal NativeRigidbody native;
-        private List<Collider> children = new List<Collider>();
-        private Joint parentJoint;
-
-        [SerializeField]
-        internal SerializableData serializableData = new SerializableData();
-
-        /// <summary>
-        /// Triggered when some object starts interacting with one of the child colliders. Only triggered if proper
-        /// collision report mode is turned on.
-        /// </summary>
-        public event Action<CollisionData> OnCollisionBegin;
-
-        /// <summary>
-        /// Triggered for every frame that an object remains interacting with one of the child colliders. Only triggered if
-        /// proper collision report mode is turned on.
-        /// </summary>
-        public event Action<CollisionData> OnCollisionStay;
-
-        /// <summary>
-        /// Triggered when some object stops interacting with one of the child colliders. Only triggered if proper collision
-        /// report mode is turned on.
-        /// </summary>
-        public event Action<CollisionData> OnCollisionEnd;
-
-        /// <summary>
-        /// Determines the mass of the object and all of its collider shapes. Only relevant if RigidbodyFlag.AutoMass or 
-        /// RigidbodyFlag.AutoTensors is turned off. Value of zero means the object is immovable (but can be rotated).
-        /// </summary>
-        public float Mass
-        {
-            get { return serializableData.mass; }
-            set
-            {
-                serializableData.mass = value;
-
-                if (native != null)
-                    native.Mass = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines if the body is kinematic. Kinematic body will not move in response to external forces (e.g. gravity,
-        /// or another object pushing it), essentially behaving like collider. Unlike a collider though, you can still move
-        /// the object and have other dynamic objects respond correctly (i.e. it will push other objects).
-        /// </summary>
-        public bool Kinematic
-        {
-            get { return serializableData.isKinematic; }
-            set
-            {
-                if (serializableData.isKinematic == value)
-                    return;
-
-                serializableData.isKinematic = value;
-
-                if (native != null)
-                {
-                    native.Kinematic = value;
-
-                    ClearColliders();
-                    UpdateColliders();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Determines if the body is sleeping. Objects that aren't moved/rotated for a while are put to sleep to reduce 
-        /// load on the physics system. You may also manually force objects to sleep or wake up.
-        /// </summary>
-        public bool Sleeping
-        {
-            get
-            {
-                if (native != null)
-                    return native.Sleeping;
-
-                return true;
-            }
-            set
-            {
-                if (native != null)
-                    native.Sleeping = value;
-            }
-        }
-
-        /// <summary>
-        /// Threshold of force and torque under which the object will be considered to be put to sleep.
-        /// </summary>
-        public float SleepThreshold
-        {
-            get { return serializableData.sleepThreshold; }
-            set
-            {
-                serializableData.sleepThreshold = value;
-
-                if (native != null)
-                    native.SleepThreshold = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines whether or not the rigidbody will have the global gravity force applied to it.
-        /// </summary>
-        public bool UseGravity
-        {
-            get { return serializableData.useGravity; }
-            set
-            {
-                serializableData.useGravity = value;
-
-                if (native != null)
-                    native.UseGravity = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines current linear velocity of the body.
-        /// </summary>
-        public Vector3 Velocity
-        {
-            get
-            {
-                if (native != null)
-                    return native.Velocity;
-
-                return Vector3.Zero;
-            }
-            set
-            {
-                if (native != null)
-                    native.Velocity = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines current angular velocity of the body.
-        /// </summary>
-        public Vector3 AngularVelocity
-        {
-            get
-            {
-                if (native != null)
-                    return native.AngularVelocity;
-
-                return Vector3.Zero;
-            }
-            set
-            {
-                if (native != null)
-                    native.AngularVelocity = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines linear drag of the body. Higher drag values means the object resists linear movement more.
-        /// </summary>
-        public float Drag
-        {
-            get { return serializableData.linearDrag; }
-            set
-            {
-                serializableData.linearDrag = value;
-
-                if (native != null)
-                    native.Drag = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines angular drag of the body. Higher drag values means the object resists angular movement more.
-        /// </summary>
-        public float AngularDrag
-        {
-            get { return serializableData.angularDrag; }
-            set
-            {
-                serializableData.angularDrag = value;
-
-                if (native != null)
-                    native.AngularDrag = value;
-            }
-        }
-
-        /// <summary>
-        /// Sets the inertia tensor in local mass space. Inertia tensor determines how difficult is to rotate the object. 
-        /// Values of zero in the inertia tensor mean the object will be unable to rotate around a specific axis. Changing
-        /// this value is only relevant if RigidbodyFlag.AutoTensors is turned off.
-        /// </summary>
-        public Vector3 InertiaTensor
-        {
-            get { return serializableData.inertiaTensor; }
-            set
-            {
-                serializableData.inertiaTensor = value;
-
-                if (native != null)
-                    native.InertiaTensor = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines position of the center of the mass. Changing this value is only relevant if RigidbodyFlag.AutoTensors
-        /// is turned off.
-        /// </summary>
-        public Vector3 CenterOfMassPosition
-        {
-            get { return serializableData.centerMassPosition; }
-            set
-            {
-                serializableData.centerMassPosition = value;
-
-                if (native != null)
-                    native.CenterOfMassPosition = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines rotation of the inertia tensor (rotation of the center of mass frame). Changing this value is only 
-        /// relevant if RigidbodyFlag.AutoTensors is turned off.
-        /// </summary>
-        public Quaternion CenterOfMassRotation
-        {
-            get { return serializableData.centerMassRotation; }
-            set
-            {
-                serializableData.centerMassRotation = value;
-
-                if (native != null)
-                    native.CenterOfMassRotation = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines maximum angular velocity of the rigidbody. Velocity will be clamped to this value.
-        /// </summary>
-        public float MaxAngularVelocity
-        {
-            get { return serializableData.maxAngularVelocity; }
-            set
-            {
-                serializableData.maxAngularVelocity = value;
-
-                if (native != null)
-                    native.MaxAngularVelocity = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines number of iterations to use when solving for position. Higher values can improve precision and 
-        /// numerical stability of the simulation.
-        /// </summary>
-        public int PositionSolverCount
-        {
-            get { return serializableData.positionSolverCount; }
-            set
-            {
-                serializableData.positionSolverCount = value;
-
-                if (native != null)
-                    serializableData.positionSolverCount = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines number of iterations to use when solving for velocity. Higher values can improve precision and 
-        /// numerical stability of the simulation.
-        /// </summary>
-        public int VelocitySolverCount
-        {
-            get { return serializableData.velocitySolverCount; }
-            set
-            {
-                serializableData.velocitySolverCount = value;
-
-                if (native != null)
-                    serializableData.velocitySolverCount = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines interpolation mode that controls how is the rigidbody transfrom updated from the physics simulation.
-        /// </summary>
-        public RigidbodyInterpolationMode InterpolationMode
-        {
-            get { return serializableData.interpolationMode; }
-            set
-            {
-                serializableData.interpolationMode = value;
-
-                if (native != null)
-                    serializableData.interpolationMode = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines which (if any) collision events are reported.
-        /// </summary>
-        public CollisionReportMode CollisionReportMode
-        {
-            get { return serializableData.collisionReportMode; }
-            set
-            {
-                if (serializableData.collisionReportMode == value)
-                    return;
-
-                serializableData.collisionReportMode = value;
-
-                foreach (var entry in children)
-                    entry.UpdateCollisionReportMode();
-            }
-        }
-
-        /// <summary>
-        /// Various flags that control the behaviour of the rigidbody.
-        /// </summary>
-        public RigidbodyFlag Flags
-        {
-            get { return serializableData.flags; }
-            set
-            {
-                if (serializableData.flags == value)
-                    return;
-
-                serializableData.flags = value;
-
-                if (native != null)
-                {
-                    native.Flags = value;
-                    native.UpdateMassDistribution();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Moves the rigidbody to a specific position. This method will ensure physically correct movement, i.e. the body
-        /// will collide with other objects along the way.
-        /// </summary>
-        /// <param name="position">New position for the body, in world space.</param>
-        public void Move(Vector3 position)
-        {
-            if (native != null)
-                native.Move(position);
-        }
-
-        /// <summary>
-        /// Rotates the rigidbody. This method will ensure physically correct rotation, i.e. the body will collide with
-        /// other objects along the way.
-        /// </summary>
-        /// <param name="rotation">New orientation of the body, in world space.</param>
-        public void Rotate(Quaternion rotation)
-        {
-            if (native != null)
-                native.Rotate(rotation);
-        }
-
-        /// <summary>
-        /// Applies a force to the center of the mass of the rigidbody. This will produce linear momentum.
-        /// </summary>
-        /// <param name="force">Force to apply.</param>
-        /// <param name="mode">Determines what type of force was applied.</param>
-        public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force)
-        {
-            if (native != null)
-                native.AddForce(force, mode);
-        }
-
-        /// <summary>
-        /// Applies a torque to the rigidbody. This will produce angular momentum.
-        /// </summary>
-        /// <param name="torque">Torque to apply.</param>
-        /// <param name="mode">Determines what type of torque was applied.</param>
-        public void AddTorque(Vector3 torque, ForceMode mode = ForceMode.Force)
-        {
-            if (native != null)
-                native.AddTorque(torque, mode);
-        }
-
-        /// <summary>
-        /// Applies a force to a specific point on the rigidbody. This will in most cases produce both linear and angular
-        /// momentum.
-        /// </summary>
-        /// <param name="force">Force to apply.</param>
-        /// <param name="position">World space point to apply the force at.</param>
-        /// <param name="mode">Determines what type of force was applied.</param>
-        public void AddForceAtPoint(Vector3 force, Vector3 position, PointForceMode mode = PointForceMode.Force)
-        {
-            if (native != null)
-                native.AddForceAtPoint(force, position, mode);
-        }
-
-        /// <summary>
-        /// Returns the total (linear + angular) velocity at a specific point. 
-        /// </summary>
-        /// <param name="position">Point in world space.</param>
-        /// <returns>Total velocity of the point.</returns>
-        public Vector3 GetVelocityAtPoint(Vector3 position)
-        {
-            if (native != null)
-                return native.GetVelocityAtPoint(position);
-
-            return position;
-        }
-
-        /// <summary>
-        /// Triggered when one of the child colliders begins touching another object.
-        /// </summary>
-        /// <param name="data">Data about the collision.</param>
-        internal void DoOnCollisionBegin(CollisionData data)
-        {
-            if (OnCollisionBegin != null)
-                OnCollisionBegin(data);
-        }
-
-        /// <summary>
-        /// Triggered when one of the child colliders ends touching another object.
-        /// </summary>
-        /// <param name="data">Data about the collision.</param>
-        internal void DoOnCollisionStay(CollisionData data)
-        {
-            if (OnCollisionStay != null)
-                OnCollisionStay(data);
-        }
-
-        /// <summary>
-        /// Triggered when one of the child colliders ends touching another object.
-        /// </summary>
-        /// <param name="data">Data about the collision.</param>
-        internal void DoOnCollisionEnd(CollisionData data)
-        {
-            if (OnCollisionEnd != null)
-                OnCollisionEnd(data);
-        }
-
-        /// <summary>
-        /// Sets that joint that this rigidbody is attached to. Allows the rigidbody to notify the joint when it moves.
-        /// </summary>
-        /// <param name="joint">Joint the rigidbody is attached to, or null if none.</param>
-        internal void SetJoint(Joint joint)
-        {
-            parentJoint = joint;
-        }
-
-        /// <summary>
-        /// Recalculates rigidbody's mass, inertia tensors and center of mass depending on the currently set child 
-        /// colliders. This should be called whenever relevant child collider properties change(like mass or shape).
-        /// 
-        /// If automatic tensor calculation is turned off then this will do nothing. If automatic mass calculation is turned
-        /// off then this will use the mass set directly on the body using <see cref="Mass"/>.
-        /// </summary>
-        internal void UpdateMassDistribution()
-        {
-            if (native != null)
-                native.UpdateMassDistribution();
-        }
-
-        /// <summary>
-        /// Unregisters all child colliders from the Rigidbody.
-        /// </summary>
-        internal void ClearColliders()
-        {
-            foreach (var collider in children)
-                collider.SetRigidbody(null, true);
-
-            children.Clear();
-
-            if (native != null)
-                native.RemoveColliders();
-        }
-
-        /// <summary>
-        /// Registers a new collider with the Rigidbody. This collider will then be used to calculate Rigidbody's geometry
-        /// used for collisions, and optionally (depending on set flags) total mass, inertia tensors and center of mass.
-        /// </summary>
-        /// <param name="collider">Collider to register.</param>
-        internal void AddCollider(Collider collider)
-	    {
-		    if (native == null)
-			    return;
-
-            children.Add(collider);
-            native.AddCollider(collider);
-	    }
-
-        /// <summary>
-        /// Unregisters the collider from the Rigidbody.
-        /// </summary>
-        /// <param name="collider">Collider to unregister.</param>
-        internal void RemoveCollider(Collider collider)
-        {
-            if (native == null)
-                return;
-
-            if (children.Exists(x => x == collider))
-            {
-                native.RemoveCollider(collider);
-                children.Remove(collider);
-            }
-        }
-
-        private void OnInitialize()
-        {
-            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
-        }
-
-        private void OnReset()
-        {
-            RestoreNative();
-        }
-
-        private void OnEnable()
-        {
-            if (native == null)
-                RestoreNative();
-        }
-
-        private void OnDisable()
-        {
-            DestroyNative();
-        }
-
-        private void OnDestroy()
-        {
-            DestroyNative();
-        }
-
-        private void OnTransformChanged(TransformChangedFlags flags)
-        {
-            if (!SceneObject.Active)
-                return;
-
-            if ((flags & TransformChangedFlags.Parent) != 0)
-            {
-                ClearColliders();
-                UpdateColliders();
-
-                if ((serializableData.flags & RigidbodyFlag.AutoTensors) != 0)
-                    native.UpdateMassDistribution();
-
-#if DEBUG
-			CheckForNestedRigibody();
-#endif
-            }
-
-            native.Position = SceneObject.Position;
-            native.Rotation = SceneObject.Rotation;
-
-            if (parentJoint != null)
-                parentJoint.NotifyRigidbodyMoved(this);
-        }
-
-        /// <summary>
-        /// Searches child scene objects for Collider components and attaches them to the rigidbody. Make sure to call
-        /// <see cref="ClearColliders"/> if you need to clear old colliders first.
-        /// </summary>
-        private void UpdateColliders()
-        {
-            Stack<SceneObject> todo = new Stack<SceneObject>();
-            todo.Push(SceneObject);
-
-            while (todo.Count > 0)
-            {
-                SceneObject currentSO = todo.Pop();
-
-                if (currentSO.GetComponent<Collider>() != null)
-                {
-                    Collider[] colliders = currentSO.GetComponents<Collider>();
-
-                    foreach (var entry in colliders)
-                    {
-                        if (!entry.IsValidParent(this))
-                            continue;
-
-                        entry.SetRigidbody(this, true);
-
-                        children.Add(entry);
-                        native.AddCollider(entry);
-                    }
-                }
-
-                int childCount = currentSO.GetNumChildren();
-                for (int i = 0; i < childCount; i++)
-                {
-                    SceneObject child = currentSO.GetChild(i);
-
-                    if (child.GetComponent<Rigidbody>() != null)
-                        continue;
-
-                    todo.Push(child);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Checks if the rigidbody is nested under another rigidbody, and throws out a warning if so.
-        /// </summary>
-        private void CheckForNestedRigibody()
-        {
-            SceneObject currentSO = SceneObject.Parent;
-
-            while (currentSO != null)
-            {
-                if (currentSO.GetComponent<Rigidbody>() != null)
-                {
-                    Debug.LogWarning("Nested Rigidbodies detected. This will result in inconsistent transformations. " +
-                        "To parent one Rigidbody to another move its colliders to the new parent, but remove the " +
-                        "Rigidbody component.");
-                    return;
-                }
-
-                currentSO = currentSO.Parent;
-            }
-        }
-
-        /// <summary>
-        /// Destroys the internal rigidbody representation.
-        /// </summary>
-        private void DestroyNative()
-        {
-            ClearColliders();
-
-            if (native != null)
-            {
-                native.Destroy();
-                native = null;
-            }
-        }
-
-        /// <summary>
-        /// Restores internal rigidbody representation and assigns it the properties stored by the component.
-        /// </summary>
-        private void RestoreNative()
-        {
-            native = new NativeRigidbody(SceneObject);
-
-            UpdateColliders();
-
-#if DEBUG
-		    CheckForNestedRigibody();
-#endif
-
-            native.Position = SceneObject.Position;
-            native.Rotation = SceneObject.Rotation;
-
-            // Note: Merge into one call to avoid many virtual function calls
-            native.PositionSolverCount = serializableData.positionSolverCount;
-            native.VelocitySolverCount = serializableData.velocitySolverCount;
-            native.MaxAngularVelocity = serializableData.maxAngularVelocity;
-            native.Drag = serializableData.linearDrag;;
-            native.AngularDrag = serializableData.angularDrag;
-            native.SleepThreshold = serializableData.sleepThreshold;
-            native.UseGravity = serializableData.useGravity;
-            native.Kinematic = serializableData.isKinematic;
-            native.InterpolationMode = serializableData.interpolationMode;
-            native.Flags = serializableData.flags;
-
-            if ((serializableData.flags & RigidbodyFlag.AutoTensors) == 0)
-            {
-                native.CenterOfMassPosition = serializableData.centerMassPosition;
-                native.CenterOfMassRotation = serializableData.centerMassRotation;
-                native.InertiaTensor = serializableData.inertiaTensor;
-                native.Mass = serializableData.mass;
-            }
-            else
-            {
-                if ((serializableData.flags & RigidbodyFlag.AutoMass) == 0)
-                    native.Mass = serializableData.mass;
-
-                native.UpdateMassDistribution();
-            }
-        }
-
-        /// <summary>
-        /// Holds all data the rigidbody component needs to persist through serialization.
-        /// </summary>
-        [SerializeObject]
-        internal class SerializableData
-        {
-            public int positionSolverCount = 4;
-            public int velocitySolverCount = 1;
-            public RigidbodyFlag flags = RigidbodyFlag.AutoTensors | RigidbodyFlag.AutoMass;
-            public RigidbodyInterpolationMode interpolationMode = RigidbodyInterpolationMode.None;
-            public CollisionReportMode collisionReportMode = CollisionReportMode.None;
-            public Vector3 centerMassPosition;
-            public Quaternion centerMassRotation;
-            public Vector3 inertiaTensor;
-            public float mass = 0.0f;
-            public float maxAngularVelocity = 1.0f;
-            public float linearDrag = 0.0f;
-            public float angularDrag = 0.0f;
-            public float sleepThreshold = 0.0f;
-            public bool useGravity = true;
-            public bool isKinematic = false;
-        }
-    }
-
-    /// <summary>
-    /// Type of force or torque that can be applied to a rigidbody.
-    /// </summary>
-    public enum ForceMode
-    {
-        /// <summary>
-        /// Value applied is a force.
-        /// </summary>
-        Force,
-        /// <summary>
-        /// Value applied is an impulse (i.e. a direct change in its linear or angular momentum).
-        /// </summary>
-		Impulse,
-        /// <summary>
-        /// Value applied is velocity.
-        /// </summary>
-		Velocity,
-        /// <summary>
-        /// Value applied is accelearation.
-        /// </summary>
-		Acceleration
-    }
-
-    /// <summary>
-    /// Type of force that can be applied to a rigidbody at an arbitrary point.
-    /// </summary>
-    public enum PointForceMode
-    {
-        /// <summary>
-        /// Value applied is a force.
-        /// </summary>
-        Force,
-        /// <summary>
-        /// Value applied is an impulse (i.e. a direct change in its linear or angular momentum).
-        /// </summary>
-		Impulse,
-    }
-
-    /// <summary>
-    /// Flags that control options of a Rigidbody object.
-    /// </summary>
-    [Flags]
-    public enum RigidbodyFlag
-    {
-        /// <summary>
-        /// No options. 
-        /// </summary>
-        None = 0x00,
-        /// <summary>
-        /// Automatically calculate center of mass transform and inertia tensors from child shapes (colliders)
-        /// </summary>
-        AutoTensors = 0x01,
-        /// <summary>
-        /// Calculate mass distribution from child shapes (colliders). Only relevant when auto-tensors is on.
-        /// </summary>
-        AutoMass = 0x02,
-        /// <summary>
-        /// Enables continous collision detection. This can prevent fast moving bodies from tunneling through each other.
-        /// This must also be enabled globally in Physics otherwise the flag will be ignored.
-        /// </summary>
-		CCD = 0x04
-    }
-
-    /// <summary>
-    /// Determines interpolation mode for a rigidbody transform during physics simulation.
-    /// </summary>
-    public enum RigidbodyInterpolationMode
-    {
-        /// <summary>
-        /// No interpolation is performed, physics transform is copied straight to the rigidbody when physics tick is done.
-        /// </summary>
-        None,
-        /// <summary>
-        /// Physics transfrom from the most recent tick is saved and slowly interpolated to during the following render 
-        /// frames. This can improve smoothness of the visible movement at framerates higher than the physics simulation 
-        /// but will introduce a delay of one physics tick to all such objects. This can create slight inconsistencies as
-        /// non-interpolated objects will have no such delay, as well as cause input lag due to the delayed reaction.
-        /// </summary>
-        Interpolate,
-        /// <summary>
-        /// Physics transform movement will be extrapolated from the last physics simulation tick. This will improve
-        /// smoothness of visible movement at framerates higher than the physics simulation. Unlike Interpolate it will
-        /// not introduce an input delay, but will introduce an error as the exact position/rotation of the objects is
-        /// extrapolated from the last frame's movement and velocities. 
-        /// </summary>
-        Extrapolate
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Collections.Generic;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Rigidbody is a dynamic physics object that can be moved using forces (or directly). It will interact with other
+    /// static and dynamic physics objects in the scene accordingly(i.e.it will push other non-kinematic rigidbodies,
+    /// and collide with static objects).
+    /// 
+    /// The shape and mass of a rigidbody is governed by its colliders. You must attach at least one collider for the
+    /// rigidbody to be valid. Colliders that are on the same scene object as the rigidbody, or on child scene objects
+    /// are automatically considered as part of the rigidbody.
+    /// </summary>
+    public sealed class Rigidbody : Component
+    {
+        internal NativeRigidbody native;
+        private List<Collider> children = new List<Collider>();
+        private Joint parentJoint;
+
+        [SerializeField]
+        internal SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Triggered when some object starts interacting with one of the child colliders. Only triggered if proper
+        /// collision report mode is turned on.
+        /// </summary>
+        public event Action<CollisionData> OnCollisionBegin;
+
+        /// <summary>
+        /// Triggered for every frame that an object remains interacting with one of the child colliders. Only triggered if
+        /// proper collision report mode is turned on.
+        /// </summary>
+        public event Action<CollisionData> OnCollisionStay;
+
+        /// <summary>
+        /// Triggered when some object stops interacting with one of the child colliders. Only triggered if proper collision
+        /// report mode is turned on.
+        /// </summary>
+        public event Action<CollisionData> OnCollisionEnd;
+
+        /// <summary>
+        /// Determines the mass of the object and all of its collider shapes. Only relevant if RigidbodyFlag.AutoMass or 
+        /// RigidbodyFlag.AutoTensors is turned off. Value of zero means the object is immovable (but can be rotated).
+        /// </summary>
+        public float Mass
+        {
+            get { return serializableData.mass; }
+            set
+            {
+                serializableData.mass = value;
+
+                if (native != null)
+                    native.Mass = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines if the body is kinematic. Kinematic body will not move in response to external forces (e.g. gravity,
+        /// or another object pushing it), essentially behaving like collider. Unlike a collider though, you can still move
+        /// the object and have other dynamic objects respond correctly (i.e. it will push other objects).
+        /// </summary>
+        public bool Kinematic
+        {
+            get { return serializableData.isKinematic; }
+            set
+            {
+                if (serializableData.isKinematic == value)
+                    return;
+
+                serializableData.isKinematic = value;
+
+                if (native != null)
+                {
+                    native.Kinematic = value;
+
+                    ClearColliders();
+                    UpdateColliders();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Determines if the body is sleeping. Objects that aren't moved/rotated for a while are put to sleep to reduce 
+        /// load on the physics system. You may also manually force objects to sleep or wake up.
+        /// </summary>
+        public bool Sleeping
+        {
+            get
+            {
+                if (native != null)
+                    return native.Sleeping;
+
+                return true;
+            }
+            set
+            {
+                if (native != null)
+                    native.Sleeping = value;
+            }
+        }
+
+        /// <summary>
+        /// Threshold of force and torque under which the object will be considered to be put to sleep.
+        /// </summary>
+        public float SleepThreshold
+        {
+            get { return serializableData.sleepThreshold; }
+            set
+            {
+                serializableData.sleepThreshold = value;
+
+                if (native != null)
+                    native.SleepThreshold = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether or not the rigidbody will have the global gravity force applied to it.
+        /// </summary>
+        public bool UseGravity
+        {
+            get { return serializableData.useGravity; }
+            set
+            {
+                serializableData.useGravity = value;
+
+                if (native != null)
+                    native.UseGravity = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines current linear velocity of the body.
+        /// </summary>
+        public Vector3 Velocity
+        {
+            get
+            {
+                if (native != null)
+                    return native.Velocity;
+
+                return Vector3.Zero;
+            }
+            set
+            {
+                if (native != null)
+                    native.Velocity = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines current angular velocity of the body.
+        /// </summary>
+        public Vector3 AngularVelocity
+        {
+            get
+            {
+                if (native != null)
+                    return native.AngularVelocity;
+
+                return Vector3.Zero;
+            }
+            set
+            {
+                if (native != null)
+                    native.AngularVelocity = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines linear drag of the body. Higher drag values means the object resists linear movement more.
+        /// </summary>
+        public float Drag
+        {
+            get { return serializableData.linearDrag; }
+            set
+            {
+                serializableData.linearDrag = value;
+
+                if (native != null)
+                    native.Drag = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines angular drag of the body. Higher drag values means the object resists angular movement more.
+        /// </summary>
+        public float AngularDrag
+        {
+            get { return serializableData.angularDrag; }
+            set
+            {
+                serializableData.angularDrag = value;
+
+                if (native != null)
+                    native.AngularDrag = value;
+            }
+        }
+
+        /// <summary>
+        /// Sets the inertia tensor in local mass space. Inertia tensor determines how difficult is to rotate the object. 
+        /// Values of zero in the inertia tensor mean the object will be unable to rotate around a specific axis. Changing
+        /// this value is only relevant if RigidbodyFlag.AutoTensors is turned off.
+        /// </summary>
+        public Vector3 InertiaTensor
+        {
+            get { return serializableData.inertiaTensor; }
+            set
+            {
+                serializableData.inertiaTensor = value;
+
+                if (native != null)
+                    native.InertiaTensor = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines position of the center of the mass. Changing this value is only relevant if RigidbodyFlag.AutoTensors
+        /// is turned off.
+        /// </summary>
+        public Vector3 CenterOfMassPosition
+        {
+            get { return serializableData.centerMassPosition; }
+            set
+            {
+                serializableData.centerMassPosition = value;
+
+                if (native != null)
+                    native.CenterOfMassPosition = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines rotation of the inertia tensor (rotation of the center of mass frame). Changing this value is only 
+        /// relevant if RigidbodyFlag.AutoTensors is turned off.
+        /// </summary>
+        public Quaternion CenterOfMassRotation
+        {
+            get { return serializableData.centerMassRotation; }
+            set
+            {
+                serializableData.centerMassRotation = value;
+
+                if (native != null)
+                    native.CenterOfMassRotation = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines maximum angular velocity of the rigidbody. Velocity will be clamped to this value.
+        /// </summary>
+        public float MaxAngularVelocity
+        {
+            get { return serializableData.maxAngularVelocity; }
+            set
+            {
+                serializableData.maxAngularVelocity = value;
+
+                if (native != null)
+                    native.MaxAngularVelocity = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines number of iterations to use when solving for position. Higher values can improve precision and 
+        /// numerical stability of the simulation.
+        /// </summary>
+        public int PositionSolverCount
+        {
+            get { return serializableData.positionSolverCount; }
+            set
+            {
+                serializableData.positionSolverCount = value;
+
+                if (native != null)
+                    serializableData.positionSolverCount = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines number of iterations to use when solving for velocity. Higher values can improve precision and 
+        /// numerical stability of the simulation.
+        /// </summary>
+        public int VelocitySolverCount
+        {
+            get { return serializableData.velocitySolverCount; }
+            set
+            {
+                serializableData.velocitySolverCount = value;
+
+                if (native != null)
+                    serializableData.velocitySolverCount = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines interpolation mode that controls how is the rigidbody transfrom updated from the physics simulation.
+        /// </summary>
+        public RigidbodyInterpolationMode InterpolationMode
+        {
+            get { return serializableData.interpolationMode; }
+            set
+            {
+                serializableData.interpolationMode = value;
+
+                if (native != null)
+                    serializableData.interpolationMode = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines which (if any) collision events are reported.
+        /// </summary>
+        public CollisionReportMode CollisionReportMode
+        {
+            get { return serializableData.collisionReportMode; }
+            set
+            {
+                if (serializableData.collisionReportMode == value)
+                    return;
+
+                serializableData.collisionReportMode = value;
+
+                foreach (var entry in children)
+                    entry.UpdateCollisionReportMode();
+            }
+        }
+
+        /// <summary>
+        /// Various flags that control the behaviour of the rigidbody.
+        /// </summary>
+        public RigidbodyFlag Flags
+        {
+            get { return serializableData.flags; }
+            set
+            {
+                if (serializableData.flags == value)
+                    return;
+
+                serializableData.flags = value;
+
+                if (native != null)
+                {
+                    native.Flags = value;
+                    native.UpdateMassDistribution();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Moves the rigidbody to a specific position. This method will ensure physically correct movement, i.e. the body
+        /// will collide with other objects along the way.
+        /// </summary>
+        /// <param name="position">New position for the body, in world space.</param>
+        public void Move(Vector3 position)
+        {
+            if (native != null)
+                native.Move(position);
+        }
+
+        /// <summary>
+        /// Rotates the rigidbody. This method will ensure physically correct rotation, i.e. the body will collide with
+        /// other objects along the way.
+        /// </summary>
+        /// <param name="rotation">New orientation of the body, in world space.</param>
+        public void Rotate(Quaternion rotation)
+        {
+            if (native != null)
+                native.Rotate(rotation);
+        }
+
+        /// <summary>
+        /// Applies a force to the center of the mass of the rigidbody. This will produce linear momentum.
+        /// </summary>
+        /// <param name="force">Force to apply.</param>
+        /// <param name="mode">Determines what type of force was applied.</param>
+        public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force)
+        {
+            if (native != null)
+                native.AddForce(force, mode);
+        }
+
+        /// <summary>
+        /// Applies a torque to the rigidbody. This will produce angular momentum.
+        /// </summary>
+        /// <param name="torque">Torque to apply.</param>
+        /// <param name="mode">Determines what type of torque was applied.</param>
+        public void AddTorque(Vector3 torque, ForceMode mode = ForceMode.Force)
+        {
+            if (native != null)
+                native.AddTorque(torque, mode);
+        }
+
+        /// <summary>
+        /// Applies a force to a specific point on the rigidbody. This will in most cases produce both linear and angular
+        /// momentum.
+        /// </summary>
+        /// <param name="force">Force to apply.</param>
+        /// <param name="position">World space point to apply the force at.</param>
+        /// <param name="mode">Determines what type of force was applied.</param>
+        public void AddForceAtPoint(Vector3 force, Vector3 position, PointForceMode mode = PointForceMode.Force)
+        {
+            if (native != null)
+                native.AddForceAtPoint(force, position, mode);
+        }
+
+        /// <summary>
+        /// Returns the total (linear + angular) velocity at a specific point. 
+        /// </summary>
+        /// <param name="position">Point in world space.</param>
+        /// <returns>Total velocity of the point.</returns>
+        public Vector3 GetVelocityAtPoint(Vector3 position)
+        {
+            if (native != null)
+                return native.GetVelocityAtPoint(position);
+
+            return position;
+        }
+
+        /// <summary>
+        /// Triggered when one of the child colliders begins touching another object.
+        /// </summary>
+        /// <param name="data">Data about the collision.</param>
+        internal void DoOnCollisionBegin(CollisionData data)
+        {
+            if (OnCollisionBegin != null)
+                OnCollisionBegin(data);
+        }
+
+        /// <summary>
+        /// Triggered when one of the child colliders ends touching another object.
+        /// </summary>
+        /// <param name="data">Data about the collision.</param>
+        internal void DoOnCollisionStay(CollisionData data)
+        {
+            if (OnCollisionStay != null)
+                OnCollisionStay(data);
+        }
+
+        /// <summary>
+        /// Triggered when one of the child colliders ends touching another object.
+        /// </summary>
+        /// <param name="data">Data about the collision.</param>
+        internal void DoOnCollisionEnd(CollisionData data)
+        {
+            if (OnCollisionEnd != null)
+                OnCollisionEnd(data);
+        }
+
+        /// <summary>
+        /// Sets that joint that this rigidbody is attached to. Allows the rigidbody to notify the joint when it moves.
+        /// </summary>
+        /// <param name="joint">Joint the rigidbody is attached to, or null if none.</param>
+        internal void SetJoint(Joint joint)
+        {
+            parentJoint = joint;
+        }
+
+        /// <summary>
+        /// Recalculates rigidbody's mass, inertia tensors and center of mass depending on the currently set child 
+        /// colliders. This should be called whenever relevant child collider properties change(like mass or shape).
+        /// 
+        /// If automatic tensor calculation is turned off then this will do nothing. If automatic mass calculation is turned
+        /// off then this will use the mass set directly on the body using <see cref="Mass"/>.
+        /// </summary>
+        internal void UpdateMassDistribution()
+        {
+            if (native != null)
+                native.UpdateMassDistribution();
+        }
+
+        /// <summary>
+        /// Unregisters all child colliders from the Rigidbody.
+        /// </summary>
+        internal void ClearColliders()
+        {
+            foreach (var collider in children)
+                collider.SetRigidbody(null, true);
+
+            children.Clear();
+
+            if (native != null)
+                native.RemoveColliders();
+        }
+
+        /// <summary>
+        /// Registers a new collider with the Rigidbody. This collider will then be used to calculate Rigidbody's geometry
+        /// used for collisions, and optionally (depending on set flags) total mass, inertia tensors and center of mass.
+        /// </summary>
+        /// <param name="collider">Collider to register.</param>
+        internal void AddCollider(Collider collider)
+	    {
+		    if (native == null)
+			    return;
+
+            children.Add(collider);
+            native.AddCollider(collider);
+	    }
+
+        /// <summary>
+        /// Unregisters the collider from the Rigidbody.
+        /// </summary>
+        /// <param name="collider">Collider to unregister.</param>
+        internal void RemoveCollider(Collider collider)
+        {
+            if (native == null)
+                return;
+
+            if (children.Exists(x => x == collider))
+            {
+                native.RemoveCollider(collider);
+                children.Remove(collider);
+            }
+        }
+
+        private void OnInitialize()
+        {
+            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
+        }
+
+        private void OnReset()
+        {
+            RestoreNative();
+        }
+
+        private void OnEnable()
+        {
+            if (native == null)
+                RestoreNative();
+        }
+
+        private void OnDisable()
+        {
+            DestroyNative();
+        }
+
+        private void OnDestroy()
+        {
+            DestroyNative();
+        }
+
+        private void OnTransformChanged(TransformChangedFlags flags)
+        {
+            if (!SceneObject.Active)
+                return;
+
+            if ((flags & TransformChangedFlags.Parent) != 0)
+            {
+                ClearColliders();
+                UpdateColliders();
+
+                if ((serializableData.flags & RigidbodyFlag.AutoTensors) != 0)
+                    native.UpdateMassDistribution();
+
+#if DEBUG
+			CheckForNestedRigibody();
+#endif
+            }
+
+            native.Position = SceneObject.Position;
+            native.Rotation = SceneObject.Rotation;
+
+            if (parentJoint != null)
+                parentJoint.NotifyRigidbodyMoved(this);
+        }
+
+        /// <summary>
+        /// Searches child scene objects for Collider components and attaches them to the rigidbody. Make sure to call
+        /// <see cref="ClearColliders"/> if you need to clear old colliders first.
+        /// </summary>
+        private void UpdateColliders()
+        {
+            Stack<SceneObject> todo = new Stack<SceneObject>();
+            todo.Push(SceneObject);
+
+            while (todo.Count > 0)
+            {
+                SceneObject currentSO = todo.Pop();
+
+                if (currentSO.GetComponent<Collider>() != null)
+                {
+                    Collider[] colliders = currentSO.GetComponents<Collider>();
+
+                    foreach (var entry in colliders)
+                    {
+                        if (!entry.IsValidParent(this))
+                            continue;
+
+                        entry.SetRigidbody(this, true);
+
+                        children.Add(entry);
+                        native.AddCollider(entry);
+                    }
+                }
+
+                int childCount = currentSO.GetNumChildren();
+                for (int i = 0; i < childCount; i++)
+                {
+                    SceneObject child = currentSO.GetChild(i);
+
+                    if (child.GetComponent<Rigidbody>() != null)
+                        continue;
+
+                    todo.Push(child);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Checks if the rigidbody is nested under another rigidbody, and throws out a warning if so.
+        /// </summary>
+        private void CheckForNestedRigibody()
+        {
+            SceneObject currentSO = SceneObject.Parent;
+
+            while (currentSO != null)
+            {
+                if (currentSO.GetComponent<Rigidbody>() != null)
+                {
+                    Debug.LogWarning("Nested Rigidbodies detected. This will result in inconsistent transformations. " +
+                        "To parent one Rigidbody to another move its colliders to the new parent, but remove the " +
+                        "Rigidbody component.");
+                    return;
+                }
+
+                currentSO = currentSO.Parent;
+            }
+        }
+
+        /// <summary>
+        /// Destroys the internal rigidbody representation.
+        /// </summary>
+        private void DestroyNative()
+        {
+            ClearColliders();
+
+            if (native != null)
+            {
+                native.Destroy();
+                native = null;
+            }
+        }
+
+        /// <summary>
+        /// Restores internal rigidbody representation and assigns it the properties stored by the component.
+        /// </summary>
+        private void RestoreNative()
+        {
+            native = new NativeRigidbody(SceneObject);
+
+            UpdateColliders();
+
+#if DEBUG
+		    CheckForNestedRigibody();
+#endif
+
+            native.Position = SceneObject.Position;
+            native.Rotation = SceneObject.Rotation;
+
+            // Note: Merge into one call to avoid many virtual function calls
+            native.PositionSolverCount = serializableData.positionSolverCount;
+            native.VelocitySolverCount = serializableData.velocitySolverCount;
+            native.MaxAngularVelocity = serializableData.maxAngularVelocity;
+            native.Drag = serializableData.linearDrag;;
+            native.AngularDrag = serializableData.angularDrag;
+            native.SleepThreshold = serializableData.sleepThreshold;
+            native.UseGravity = serializableData.useGravity;
+            native.Kinematic = serializableData.isKinematic;
+            native.InterpolationMode = serializableData.interpolationMode;
+            native.Flags = serializableData.flags;
+
+            if ((serializableData.flags & RigidbodyFlag.AutoTensors) == 0)
+            {
+                native.CenterOfMassPosition = serializableData.centerMassPosition;
+                native.CenterOfMassRotation = serializableData.centerMassRotation;
+                native.InertiaTensor = serializableData.inertiaTensor;
+                native.Mass = serializableData.mass;
+            }
+            else
+            {
+                if ((serializableData.flags & RigidbodyFlag.AutoMass) == 0)
+                    native.Mass = serializableData.mass;
+
+                native.UpdateMassDistribution();
+            }
+        }
+
+        /// <summary>
+        /// Holds all data the rigidbody component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        internal class SerializableData
+        {
+            public int positionSolverCount = 4;
+            public int velocitySolverCount = 1;
+            public RigidbodyFlag flags = RigidbodyFlag.AutoTensors | RigidbodyFlag.AutoMass;
+            public RigidbodyInterpolationMode interpolationMode = RigidbodyInterpolationMode.None;
+            public CollisionReportMode collisionReportMode = CollisionReportMode.None;
+            public Vector3 centerMassPosition = Vector3.Zero;
+            public Quaternion centerMassRotation = Quaternion.Identity;
+            public Vector3 inertiaTensor = Vector3.Zero;
+            public float mass = 0.0f;
+            public float maxAngularVelocity = 1.0f;
+            public float linearDrag = 0.0f;
+            public float angularDrag = 0.0f;
+            public float sleepThreshold = 0.0f;
+            public bool useGravity = true;
+            public bool isKinematic = false;
+        }
+    }
+
+    /// <summary>
+    /// Type of force or torque that can be applied to a rigidbody.
+    /// </summary>
+    public enum ForceMode
+    {
+        /// <summary>
+        /// Value applied is a force.
+        /// </summary>
+        Force,
+        /// <summary>
+        /// Value applied is an impulse (i.e. a direct change in its linear or angular momentum).
+        /// </summary>
+		Impulse,
+        /// <summary>
+        /// Value applied is velocity.
+        /// </summary>
+		Velocity,
+        /// <summary>
+        /// Value applied is accelearation.
+        /// </summary>
+		Acceleration
+    }
+
+    /// <summary>
+    /// Type of force that can be applied to a rigidbody at an arbitrary point.
+    /// </summary>
+    public enum PointForceMode
+    {
+        /// <summary>
+        /// Value applied is a force.
+        /// </summary>
+        Force,
+        /// <summary>
+        /// Value applied is an impulse (i.e. a direct change in its linear or angular momentum).
+        /// </summary>
+		Impulse,
+    }
+
+    /// <summary>
+    /// Flags that control options of a Rigidbody object.
+    /// </summary>
+    [Flags]
+    public enum RigidbodyFlag
+    {
+        /// <summary>
+        /// No options. 
+        /// </summary>
+        None = 0x00,
+        /// <summary>
+        /// Automatically calculate center of mass transform and inertia tensors from child shapes (colliders)
+        /// </summary>
+        AutoTensors = 0x01,
+        /// <summary>
+        /// Calculate mass distribution from child shapes (colliders). Only relevant when auto-tensors is on.
+        /// </summary>
+        AutoMass = 0x02,
+        /// <summary>
+        /// Enables continous collision detection. This can prevent fast moving bodies from tunneling through each other.
+        /// This must also be enabled globally in Physics otherwise the flag will be ignored.
+        /// </summary>
+		CCD = 0x04
+    }
+
+    /// <summary>
+    /// Determines interpolation mode for a rigidbody transform during physics simulation.
+    /// </summary>
+    public enum RigidbodyInterpolationMode
+    {
+        /// <summary>
+        /// No interpolation is performed, physics transform is copied straight to the rigidbody when physics tick is done.
+        /// </summary>
+        None,
+        /// <summary>
+        /// Physics transfrom from the most recent tick is saved and slowly interpolated to during the following render 
+        /// frames. This can improve smoothness of the visible movement at framerates higher than the physics simulation 
+        /// but will introduce a delay of one physics tick to all such objects. This can create slight inconsistencies as
+        /// non-interpolated objects will have no such delay, as well as cause input lag due to the delayed reaction.
+        /// </summary>
+        Interpolate,
+        /// <summary>
+        /// Physics transform movement will be extrapolated from the last physics simulation tick. This will improve
+        /// smoothness of visible movement at framerates higher than the physics simulation. Unlike Interpolate it will
+        /// not introduce an input delay, but will introduce an error as the exact position/rotation of the objects is
+        /// extrapolated from the last frame's movement and velocities. 
+        /// </summary>
+        Extrapolate
+    }
+}

+ 584 - 583
Source/MBansheeEngine/SceneObject.cs

@@ -1,583 +1,584 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// An object in the scene graph. It has a position, place in the hierarchy and optionally a number of attached 
-    /// components.
-    /// </summary>
-    public sealed class SceneObject : GameObject
-    {
-        /// <summary>
-        /// Name of the scene object.
-        /// </summary>
-        public string Name
-        {
-            get { return Internal_GetName(mCachedPtr); }
-            set { Internal_SetName(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// Parent in the scene object hierarchy. Null for hierarchy root.
-        /// </summary>
-        public SceneObject Parent
-        {
-            get { return Internal_GetParent(mCachedPtr); }
-            set { Internal_SetParent(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// Determines if the object's components are being updated or not.
-        /// </summary>
-        public bool Active
-        {
-            get { return Internal_GetActive(mCachedPtr); }
-            set { Internal_SetActive(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// World position. This includes local position of this object, plus position offset of any parents.
-        /// </summary>
-        public Vector3 Position
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetPosition(mCachedPtr, out value);
-                return value;
-            }
-
-            set
-            {
-                Internal_SetPosition(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// Local space position (relative to the parent).
-        /// </summary>
-        public Vector3 LocalPosition
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetLocalPosition(mCachedPtr, out value);
-                return value;
-            }
-
-            set
-            {
-                Internal_SetLocalPosition(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// World rotation. This includes local rotation of this object, plus rotation of any parents.
-        /// </summary>
-        public Quaternion Rotation
-        {
-            get
-            {
-                Quaternion value;
-                Internal_GetRotation(mCachedPtr, out value);
-                return value;
-            }
-
-            set
-            {
-                Internal_SetRotation(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// Local rotation (relative to the parent).
-        /// </summary>
-        public Quaternion LocalRotation
-        {
-            get
-            {
-                Quaternion value;
-                Internal_GetLocalRotation(mCachedPtr, out value);
-                return value;
-            }
-
-            set
-            {
-                Internal_SetLocalRotation(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// World space scale. This includes local scale of this object, plus scale of any parent.
-        /// </summary>
-        public Vector3 Scale
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetScale(mCachedPtr, out value);
-                return value;
-            }
-        }
-
-        /// <summary>
-        /// Local scale (relative to the parent).
-        /// </summary>
-        public Vector3 LocalScale
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetLocalScale(mCachedPtr, out value);
-                return value;
-            }
-
-            set
-            {
-                Internal_SetLocalScale(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// Returns the world transform matrix. This matrix accounts for position, rotation and scale transformations
-        /// relative to the world basis.
-        /// </summary>
-        public Matrix4 WorldTransform
-        {
-            get
-            {
-                Matrix4 value;
-                Internal_GetWorldTransform(mCachedPtr, out value);
-                return value;
-            }
-        }
-
-        /// <summary>
-        /// Returns the local transform matrix. This matrix accounts for position, rotation and scale transformations
-        /// relative to the parent's basis.
-        /// </summary>
-        public Matrix4 LocalTransform
-        {
-            get
-            {
-                Matrix4 value;
-                Internal_GetLocalTransform(mCachedPtr, out value);
-                return value;
-            }
-        }
-
-        /// <summary>
-        /// Direction in world space that points along the local negative Z axis.
-        /// </summary>
-        public Vector3 Forward
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetForward(mCachedPtr, out value);
-                return value;
-            }
-            set
-            {
-                Internal_SetForward(mCachedPtr, ref value);
-            }
-        }
-
-        /// <summary>
-        /// Direction in world space that points along the local positive X axis.
-        /// </summary>
-        public Vector3 Right
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetRight(mCachedPtr, out value);
-                return value;
-            }
-        }
-
-        /// <summary>
-        /// Direction in world space that points along the local positive Y axis.
-        /// </summary>
-        public Vector3 Up
-        {
-            get
-            {
-                Vector3 value;
-                Internal_GetUp(mCachedPtr, out value);
-                return value;
-            }
-        }
-
-        /// <summary>
-        /// Constructor for internal use by the runtime.
-        /// </summary>
-        private SceneObject()
-        {
-            
-        }
-
-        /// <summary>
-        /// Creates a new scene object. Object will initially be parented to scene root and placed at the world origin.
-        /// </summary>
-        /// <param name="name">Name of the scene object.</param>
-        public SceneObject(string name)
-        {
-            Internal_CreateInstance(this, name, 0);
-        }
-
-        /// <summary>
-        /// Creates a new scene object. Object will initially be parented to scene root and placed at the world origin.
-        /// </summary>
-        /// <param name="name">Name of the scene object.</param>
-        /// <param name="isInternal">Specifies this object is for internal use by the runtime. Internal object will not
-        ///                          get saved, nor will they be displayed in the editor during non-debug mode.</param>
-        internal SceneObject(string name, bool isInternal)
-        {
-            if(isInternal)
-                Internal_CreateInstance(this, name, (int)(SceneObjectEditorFlags.DontSave | SceneObjectEditorFlags.Internal | SceneObjectEditorFlags.Persistent));
-            else
-                Internal_CreateInstance(this, name, 0);
-        }
-
-        /// <summary>
-        /// Constructs a new component of the specified type and adds it to the internal component list.
-        /// </summary>
-        /// <typeparam name="T">Type of component to create.</typeparam>
-        /// <returns>Instance of the new component.</returns>
-        public T AddComponent<T>() where T : Component
-        {
-            return (T)Component.Internal_AddComponent(this, typeof (T));
-        }
-
-        /// <summary>
-        /// Constructs a new component of the specified type and adds it to the internal component list.
-        /// </summary>
-        /// <param name="type">Type of component to create.</param>
-        /// <returns>Instance of the new component.</returns>
-        public Component AddComponent(Type type)
-        {
-            return Component.Internal_AddComponent(this, type);
-        }
-
-        /// <summary>
-        /// Searches for a component of a specific type. If there are multiple components matching the type, only the first
-        /// one found is returned.
-        /// </summary>
-        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
-        /// </typeparam>
-        /// <returns>Component instance if found, null otherwise.</returns>
-        public T GetComponent<T>() where T : Component
-        {
-            return (T)Component.Internal_GetComponent(this, typeof(T));
-        }
-
-        /// <summary>
-        /// Searches for all components of a specific type. 
-        /// </summary>
-        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
-        /// </typeparam>
-        /// <returns>All components matching the specified type.</returns>
-        public T[] GetComponents<T>() where T : Component
-        {
-            return (T[])Component.Internal_GetComponentsPerType(this, typeof(T));
-        }
-
-        /// <summary>
-        /// Returns a list of all components attached to this object.
-        /// </summary>
-        /// <returns>All components attached to this object.</returns>
-        public Component[] GetComponents()
-        {
-            return Component.Internal_GetComponents(this);
-        }
-
-        /// <summary>
-        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
-        /// one found is removed.
-        /// </summary>
-        /// <typeparam name="T">Type of the component to remove. Includes any components derived from the type.</typeparam>
-        public void RemoveComponent<T>() where T : Component
-        {
-            Component.Internal_RemoveComponent(this, typeof(T));
-        }
-
-        /// <summary>
-        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
-        /// one found is removed.
-        /// </summary>
-        /// <param name="type">Type of the component to remove. Includes any components derived from the type.</param>
-        public void RemoveComponent(Type type)
-        {
-            Component.Internal_RemoveComponent(this, type);
-        }
-
-        /// <summary>
-        /// Returns the number of child scene objects this object is parent to.
-        /// </summary>
-        /// <returns>Number of child scene objects.</returns>
-        public int GetNumChildren()
-        {
-            int value;
-            Internal_GetNumChildren(mCachedPtr, out value);
-            return value;
-        }
-
-        /// <summary>
-        /// Returns a child scene object.
-        /// </summary>
-        /// <param name="idx">Index of the child scene object to retrieve.</param>
-        /// <returns>Instance of the child scene object, or null if index is out of range.</returns>
-        public SceneObject GetChild(int idx)
-        {
-            return Internal_GetChild(mCachedPtr, idx);
-        }
-
-        /// <summary>
-        /// Searches the child objects for an object matching the specified name.
-        /// </summary>
-        /// <param name="name">Name of the object to locate.</param>
-        /// <param name="recursive">If true all descendants of the scene object will be searched, otherwise only immediate 
-        ///                         children.</param>
-        /// <returns>First found scene object, or empty handle if none found.</returns>
-        public SceneObject FindChild(string name, bool recursive = true)
-        {
-            return Internal_FindChild(mCachedPtr, name, recursive);
-        }
-
-        /// <summary>
-        /// Searches the child objects for objects matching the specified name.
-        /// </summary>
-        /// <param name="name">Name of the objects to locate.</param>
-        /// <param name="recursive">If true all descendants of the scene object will be searched, otherwise only immediate 
-        ///                         children.</param>
-        /// <returns>All scene objects matching the specified name.</returns>
-        public SceneObject[] FindChildren(string name, bool recursive = true)
-        {
-            return Internal_FindChildren(mCachedPtr, name, recursive);
-        }
-
-        /// <summary>
-        /// Orients the object so it is looking at the provided location.
-        /// </summary>
-        /// <param name="position">Position in local space where to look at.</param>
-        public void LookAt(Vector3 position)
-        {
-            Vector3 up = Vector3.YAxis;
-            Internal_LookAt(mCachedPtr, ref position, ref up);
-        }
-
-        /// <summary>
-        /// Orients the object so it is looking at the provided location.
-        /// </summary>
-        /// <param name="position">Position in world space where to look at.</param>
-        /// <param name="up">Determines the object's Y axis orientation.</param>
-        public void LookAt(Vector3 position, Vector3 up)
-        {
-            Internal_LookAt(mCachedPtr, ref position, ref up);
-        }
-
-        /// <summary>
-        /// Moves the object's position by the vector offset provided along world axes.
-        /// </summary>
-        /// <param name="amount">Amount and direction to move the object along.</param>
-        public void Move(Vector3 amount)
-        {
-            Internal_Move(mCachedPtr, ref amount);
-        }
-
-        /// <summary>
-        /// Moves the object's position by the vector offset provided along local axes.
-        /// </summary>
-        /// <param name="amount">Amount and direction to move the object along.</param>
-        public void MoveLocal(Vector3 amount)
-        {
-            Internal_MoveLocal(mCachedPtr, ref amount);
-        }
-
-        /// <summary>
-        /// Rotates the object by the quaternion, in world space.
-        /// </summary>
-        /// <param name="amount">Quaternion that specifies the rotation.</param>
-        public void Rotate(Quaternion amount)
-        {
-            Internal_Rotate(mCachedPtr, ref amount);
-        }
-
-        /// <summary>
-        /// Rotates around local Z axis.
-        /// </summary>
-        /// <param name="angle">Angle to rotate by.</param>
-        public void Roll(Degree angle)
-        {
-            Radian radianAngle = angle;
-            Internal_Roll(mCachedPtr, ref radianAngle);
-        }
-
-        /// <summary>
-        /// Rotates around local Y axis.
-        /// </summary>
-        /// <param name="angle">Angle to rotate by.</param>
-        public void Yaw(Degree angle)
-        {
-            Radian radianAngle = angle;
-            Internal_Yaw(mCachedPtr, ref radianAngle);
-        }
-
-        /// <summary>
-        /// Rotates around local X axis.
-        /// </summary>
-        /// <param name="angle">Angle to rotate by.</param>
-        public void Pitch(Degree angle)
-        {
-            Radian radianAngle = angle;
-            Internal_Pitch(mCachedPtr, ref radianAngle);
-        }
-
-        /// <summary>
-        /// Destroys the scene object, removing it from scene and stopping component updates.
-        /// </summary>
-        /// <param name="immediate">If true the scene object will be fully destroyed immediately. This means that objects
-        ///                         that are still referencing this scene object might fail. Normally destruction is delayed
-        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
-        public void Destroy(bool immediate = false)
-        {
-            Internal_Destroy(mCachedPtr, immediate);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(SceneObject instance, string name, int flags);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetName(IntPtr nativeInstance, string name);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern string Internal_GetName(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetActive(IntPtr nativeInstance, bool value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetActive(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetParent(IntPtr nativeInstance, SceneObject parent);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SceneObject Internal_GetParent(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetNumChildren(IntPtr nativeInstance, out int value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SceneObject Internal_GetChild(IntPtr nativeInstance, int idx);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SceneObject Internal_FindChild(IntPtr nativeInstance, string name, bool recursive);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SceneObject[] Internal_FindChildren(IntPtr nativeInstance, string name, bool recursive);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetLocalPosition(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetRotation(IntPtr nativeInstance, out Quaternion value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetLocalRotation(IntPtr nativeInstance, out Quaternion value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetScale(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetLocalScale(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPosition(IntPtr nativeInstance, ref Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLocalPosition(IntPtr nativeInstance, ref Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRotation(IntPtr nativeInstance, ref Quaternion value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLocalRotation(IntPtr nativeInstance, ref Quaternion value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLocalScale(IntPtr nativeInstance, ref Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetLocalTransform(IntPtr nativeInstance, out Matrix4 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetWorldTransform(IntPtr nativeInstance, out Matrix4 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_LookAt(IntPtr nativeInstance, ref Vector3 direction, ref Vector3 up);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Move(IntPtr nativeInstance, ref Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_MoveLocal(IntPtr nativeInstance, ref  Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Rotate(IntPtr nativeInstance, ref Quaternion value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Roll(IntPtr nativeInstance, ref Radian value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Yaw(IntPtr nativeInstance, ref Radian value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Pitch(IntPtr nativeInstance, ref Radian value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetForward(IntPtr nativeInstance, ref Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetForward(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetUp(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetRight(IntPtr nativeInstance, out Vector3 value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
-    }
-
-    /// <summary>
-    /// Flags that can be used for controlling scene object behaviour.
-    /// </summary>
-    internal enum SceneObjectEditorFlags // Note: Must match C++ enum SceneObjectFlags
-    {
-        /// <summary>Object wont be in the main scene and its components won't receive updates.</summary>
-        DontInstantiate = 0x01,
-
-        /// <summary> Object will be skipped when saving the scene hierarchy or a prefab.</summary>
-        DontSave = 0x02,
-
-        /// <summary>
-        /// Object will remain in the scene even after scene clear, unless destroyed directly. This only works with 
-        /// top-level objects.
-        /// </summary>
-        Persistent = 0x04,
-
-        /// <summary>
-        /// Provides a hint to external systems that his object is used by engine internals. For example, those systems 
-        /// might not want to display those objects together with the user created ones.
-        /// </summary>
-        Internal = 0x08
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// An object in the scene graph. It has a position, place in the hierarchy and optionally a number of attached 
+    /// components.
+    /// </summary>
+    public sealed class SceneObject : GameObject
+    {
+        /// <summary>
+        /// Name of the scene object.
+        /// </summary>
+        public string Name
+        {
+            get { return Internal_GetName(mCachedPtr); }
+            set { Internal_SetName(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// Parent in the scene object hierarchy. Null for hierarchy root.
+        /// </summary>
+        public SceneObject Parent
+        {
+            get { return Internal_GetParent(mCachedPtr); }
+            set { Internal_SetParent(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// Determines if the object's components are being updated or not.
+        /// </summary>
+        public bool Active
+        {
+            get { return Internal_GetActive(mCachedPtr); }
+            set { Internal_SetActive(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// World position. This includes local position of this object, plus position offset of any parents.
+        /// </summary>
+        public Vector3 Position
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetPosition(mCachedPtr, out value);
+                return value;
+            }
+
+            set
+            {
+                Internal_SetPosition(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// Local space position (relative to the parent).
+        /// </summary>
+        public Vector3 LocalPosition
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetLocalPosition(mCachedPtr, out value);
+                return value;
+            }
+
+            set
+            {
+                Internal_SetLocalPosition(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// World rotation. This includes local rotation of this object, plus rotation of any parents.
+        /// </summary>
+        public Quaternion Rotation
+        {
+            get
+            {
+                Quaternion value;
+                Internal_GetRotation(mCachedPtr, out value);
+                return value;
+            }
+
+            set
+            {
+                Internal_SetRotation(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// Local rotation (relative to the parent).
+        /// </summary>
+        public Quaternion LocalRotation
+        {
+            get
+            {
+                Quaternion value;
+                Internal_GetLocalRotation(mCachedPtr, out value);
+                return value;
+            }
+
+            set
+            {
+                Internal_SetLocalRotation(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// World space scale. This includes local scale of this object, plus scale of any parent.
+        /// </summary>
+        public Vector3 Scale
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetScale(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        /// <summary>
+        /// Local scale (relative to the parent).
+        /// </summary>
+        public Vector3 LocalScale
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetLocalScale(mCachedPtr, out value);
+                return value;
+            }
+
+            set
+            {
+                Internal_SetLocalScale(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// Returns the world transform matrix. This matrix accounts for position, rotation and scale transformations
+        /// relative to the world basis.
+        /// </summary>
+        public Matrix4 WorldTransform
+        {
+            get
+            {
+                Matrix4 value;
+                Internal_GetWorldTransform(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        /// <summary>
+        /// Returns the local transform matrix. This matrix accounts for position, rotation and scale transformations
+        /// relative to the parent's basis.
+        /// </summary>
+        public Matrix4 LocalTransform
+        {
+            get
+            {
+                Matrix4 value;
+                Internal_GetLocalTransform(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        /// <summary>
+        /// Direction in world space that points along the local negative Z axis.
+        /// </summary>
+        public Vector3 Forward
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetForward(mCachedPtr, out value);
+                return value;
+            }
+            set
+            {
+                Internal_SetForward(mCachedPtr, ref value);
+            }
+        }
+
+        /// <summary>
+        /// Direction in world space that points along the local positive X axis.
+        /// </summary>
+        public Vector3 Right
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetRight(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        /// <summary>
+        /// Direction in world space that points along the local positive Y axis.
+        /// </summary>
+        public Vector3 Up
+        {
+            get
+            {
+                Vector3 value;
+                Internal_GetUp(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        /// <summary>
+        /// Constructor for internal use by the runtime.
+        /// </summary>
+        private SceneObject()
+        {
+            
+        }
+
+        /// <summary>
+        /// Creates a new scene object. Object will initially be parented to scene root and placed at the world origin.
+        /// </summary>
+        /// <param name="name">Name of the scene object.</param>
+        public SceneObject(string name)
+        {
+            Internal_CreateInstance(this, name, 0);
+        }
+
+        /// <summary>
+        /// Creates a new scene object. Object will initially be parented to scene root and placed at the world origin.
+        /// </summary>
+        /// <param name="name">Name of the scene object.</param>
+        /// <param name="isInternal">Specifies this object is for internal use by the runtime. Internal object will not
+        ///                          get saved, nor will they be displayed in the editor during non-debug mode.</param>
+        internal SceneObject(string name, bool isInternal)
+        {
+            if(isInternal)
+                Internal_CreateInstance(this, name, (int)(SceneObjectEditorFlags.DontSave | SceneObjectEditorFlags.Internal | SceneObjectEditorFlags.Persistent));
+            else
+                Internal_CreateInstance(this, name, 0);
+        }
+
+        /// <summary>
+        /// Constructs a new component of the specified type and adds it to the internal component list.
+        /// </summary>
+        /// <typeparam name="T">Type of component to create.</typeparam>
+        /// <returns>Instance of the new component.</returns>
+        public T AddComponent<T>() where T : Component
+        {
+            return (T)Component.Internal_AddComponent(this, typeof (T));
+        }
+
+        /// <summary>
+        /// Constructs a new component of the specified type and adds it to the internal component list.
+        /// </summary>
+        /// <param name="type">Type of component to create.</param>
+        /// <returns>Instance of the new component.</returns>
+        public Component AddComponent(Type type)
+        {
+            return Component.Internal_AddComponent(this, type);
+        }
+
+        /// <summary>
+        /// Searches for a component of a specific type. If there are multiple components matching the type, only the first
+        /// one found is returned.
+        /// </summary>
+        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
+        /// </typeparam>
+        /// <returns>Component instance if found, null otherwise.</returns>
+        public T GetComponent<T>() where T : Component
+        {
+            return (T)Component.Internal_GetComponent(this, typeof(T));
+        }
+
+        /// <summary>
+        /// Searches for all components of a specific type. 
+        /// </summary>
+        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
+        /// </typeparam>
+        /// <returns>All components matching the specified type.</returns>
+        public T[] GetComponents<T>() where T : Component
+        {
+            Component[] components = Component.Internal_GetComponentsPerType(this, typeof (T));
+            return Array.ConvertAll(components, x => (T) x);
+        }
+
+        /// <summary>
+        /// Returns a list of all components attached to this object.
+        /// </summary>
+        /// <returns>All components attached to this object.</returns>
+        public Component[] GetComponents()
+        {
+            return Component.Internal_GetComponents(this);
+        }
+
+        /// <summary>
+        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
+        /// one found is removed.
+        /// </summary>
+        /// <typeparam name="T">Type of the component to remove. Includes any components derived from the type.</typeparam>
+        public void RemoveComponent<T>() where T : Component
+        {
+            Component.Internal_RemoveComponent(this, typeof(T));
+        }
+
+        /// <summary>
+        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
+        /// one found is removed.
+        /// </summary>
+        /// <param name="type">Type of the component to remove. Includes any components derived from the type.</param>
+        public void RemoveComponent(Type type)
+        {
+            Component.Internal_RemoveComponent(this, type);
+        }
+
+        /// <summary>
+        /// Returns the number of child scene objects this object is parent to.
+        /// </summary>
+        /// <returns>Number of child scene objects.</returns>
+        public int GetNumChildren()
+        {
+            int value;
+            Internal_GetNumChildren(mCachedPtr, out value);
+            return value;
+        }
+
+        /// <summary>
+        /// Returns a child scene object.
+        /// </summary>
+        /// <param name="idx">Index of the child scene object to retrieve.</param>
+        /// <returns>Instance of the child scene object, or null if index is out of range.</returns>
+        public SceneObject GetChild(int idx)
+        {
+            return Internal_GetChild(mCachedPtr, idx);
+        }
+
+        /// <summary>
+        /// Searches the child objects for an object matching the specified name.
+        /// </summary>
+        /// <param name="name">Name of the object to locate.</param>
+        /// <param name="recursive">If true all descendants of the scene object will be searched, otherwise only immediate 
+        ///                         children.</param>
+        /// <returns>First found scene object, or empty handle if none found.</returns>
+        public SceneObject FindChild(string name, bool recursive = true)
+        {
+            return Internal_FindChild(mCachedPtr, name, recursive);
+        }
+
+        /// <summary>
+        /// Searches the child objects for objects matching the specified name.
+        /// </summary>
+        /// <param name="name">Name of the objects to locate.</param>
+        /// <param name="recursive">If true all descendants of the scene object will be searched, otherwise only immediate 
+        ///                         children.</param>
+        /// <returns>All scene objects matching the specified name.</returns>
+        public SceneObject[] FindChildren(string name, bool recursive = true)
+        {
+            return Internal_FindChildren(mCachedPtr, name, recursive);
+        }
+
+        /// <summary>
+        /// Orients the object so it is looking at the provided location.
+        /// </summary>
+        /// <param name="position">Position in local space where to look at.</param>
+        public void LookAt(Vector3 position)
+        {
+            Vector3 up = Vector3.YAxis;
+            Internal_LookAt(mCachedPtr, ref position, ref up);
+        }
+
+        /// <summary>
+        /// Orients the object so it is looking at the provided location.
+        /// </summary>
+        /// <param name="position">Position in world space where to look at.</param>
+        /// <param name="up">Determines the object's Y axis orientation.</param>
+        public void LookAt(Vector3 position, Vector3 up)
+        {
+            Internal_LookAt(mCachedPtr, ref position, ref up);
+        }
+
+        /// <summary>
+        /// Moves the object's position by the vector offset provided along world axes.
+        /// </summary>
+        /// <param name="amount">Amount and direction to move the object along.</param>
+        public void Move(Vector3 amount)
+        {
+            Internal_Move(mCachedPtr, ref amount);
+        }
+
+        /// <summary>
+        /// Moves the object's position by the vector offset provided along local axes.
+        /// </summary>
+        /// <param name="amount">Amount and direction to move the object along.</param>
+        public void MoveLocal(Vector3 amount)
+        {
+            Internal_MoveLocal(mCachedPtr, ref amount);
+        }
+
+        /// <summary>
+        /// Rotates the object by the quaternion, in world space.
+        /// </summary>
+        /// <param name="amount">Quaternion that specifies the rotation.</param>
+        public void Rotate(Quaternion amount)
+        {
+            Internal_Rotate(mCachedPtr, ref amount);
+        }
+
+        /// <summary>
+        /// Rotates around local Z axis.
+        /// </summary>
+        /// <param name="angle">Angle to rotate by.</param>
+        public void Roll(Degree angle)
+        {
+            Radian radianAngle = angle;
+            Internal_Roll(mCachedPtr, ref radianAngle);
+        }
+
+        /// <summary>
+        /// Rotates around local Y axis.
+        /// </summary>
+        /// <param name="angle">Angle to rotate by.</param>
+        public void Yaw(Degree angle)
+        {
+            Radian radianAngle = angle;
+            Internal_Yaw(mCachedPtr, ref radianAngle);
+        }
+
+        /// <summary>
+        /// Rotates around local X axis.
+        /// </summary>
+        /// <param name="angle">Angle to rotate by.</param>
+        public void Pitch(Degree angle)
+        {
+            Radian radianAngle = angle;
+            Internal_Pitch(mCachedPtr, ref radianAngle);
+        }
+
+        /// <summary>
+        /// Destroys the scene object, removing it from scene and stopping component updates.
+        /// </summary>
+        /// <param name="immediate">If true the scene object will be fully destroyed immediately. This means that objects
+        ///                         that are still referencing this scene object might fail. Normally destruction is delayed
+        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
+        public void Destroy(bool immediate = false)
+        {
+            Internal_Destroy(mCachedPtr, immediate);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(SceneObject instance, string name, int flags);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetName(IntPtr nativeInstance, string name);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetName(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetActive(IntPtr nativeInstance, bool value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetActive(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetParent(IntPtr nativeInstance, SceneObject parent);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject Internal_GetParent(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetNumChildren(IntPtr nativeInstance, out int value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject Internal_GetChild(IntPtr nativeInstance, int idx);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject Internal_FindChild(IntPtr nativeInstance, string name, bool recursive);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject[] Internal_FindChildren(IntPtr nativeInstance, string name, bool recursive);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetLocalPosition(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRotation(IntPtr nativeInstance, out Quaternion value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetLocalRotation(IntPtr nativeInstance, out Quaternion value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetScale(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetLocalScale(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr nativeInstance, ref Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLocalPosition(IntPtr nativeInstance, ref Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRotation(IntPtr nativeInstance, ref Quaternion value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLocalRotation(IntPtr nativeInstance, ref Quaternion value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLocalScale(IntPtr nativeInstance, ref Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetLocalTransform(IntPtr nativeInstance, out Matrix4 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetWorldTransform(IntPtr nativeInstance, out Matrix4 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_LookAt(IntPtr nativeInstance, ref Vector3 direction, ref Vector3 up);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Move(IntPtr nativeInstance, ref Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_MoveLocal(IntPtr nativeInstance, ref  Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Rotate(IntPtr nativeInstance, ref Quaternion value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Roll(IntPtr nativeInstance, ref Radian value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Yaw(IntPtr nativeInstance, ref Radian value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Pitch(IntPtr nativeInstance, ref Radian value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetForward(IntPtr nativeInstance, ref Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetForward(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetUp(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRight(IntPtr nativeInstance, out Vector3 value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
+    }
+
+    /// <summary>
+    /// Flags that can be used for controlling scene object behaviour.
+    /// </summary>
+    internal enum SceneObjectEditorFlags // Note: Must match C++ enum SceneObjectFlags
+    {
+        /// <summary>Object wont be in the main scene and its components won't receive updates.</summary>
+        DontInstantiate = 0x01,
+
+        /// <summary> Object will be skipped when saving the scene hierarchy or a prefab.</summary>
+        DontSave = 0x02,
+
+        /// <summary>
+        /// Object will remain in the scene even after scene clear, unless destroyed directly. This only works with 
+        /// top-level objects.
+        /// </summary>
+        Persistent = 0x04,
+
+        /// <summary>
+        /// Provides a hint to external systems that his object is used by engine internals. For example, those systems 
+        /// might not want to display those objects together with the user created ones.
+        /// </summary>
+        Internal = 0x08
+    }
+}

+ 167 - 161
Source/SBansheeEngine/Include/BsManagedComponent.h

@@ -1,162 +1,168 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsScriptEnginePrerequisites.h"
-#include "BsComponent.h"
-#include <mono/jit/jit.h>
-
-namespace BansheeEngine
-{
-	struct ComponentBackupData;
-
-	/**
-	 * Component that internally wraps a managed component object that can be of user-defined type. Acts as interop interop
-	 * layer between native Component and a managed user defined component type since managed types cannot simply derive
-	 * from Component to implement its functionality.
-	 */
-	class BS_SCR_BE_EXPORT ManagedComponent : public Component
-	{
-	public:
-		~ManagedComponent();
-
-		/**	Returns managed component object instance. */
-		MonoObject* getManagedInstance() const { return mManagedInstance; }
-
-		/**	Returns managed type of the component. */
-		MonoReflectionType* getRuntimeType() const { return mRuntimeType; }
-
-		/**	Returns namespace of the managed component. */
-		const String& getManagedNamespace() const { return mNamespace; }
-
-		/**	Returns type name of the managed component. */
-		const String& getManagedTypeName() const { return mTypeName; }
-
-		/**	Returns namespace and type name of the component in format "namespace.typename". */
-		const String& getManagedFullTypeName() const { return mFullTypeName; }
-
-		/**
-		 * Serializes the internal managed component.
-		 *
-		 * @param[in]	clearExisting	Should the managed component handle be released. (Will trigger a finalizer if this
-		 *								is the last reference to it)
-		 * @return						An object containing the serialized component. You can provide this to restore()
-		 *								method to re-create the original component.
-		 */
-		ComponentBackupData backup(bool clearExisting = true);
-
-		/**
-		 * Restores a component from previously serialized data.
-		 *
-		 * @param[in]	instance	New instance of the managed component. Must be of the valid component type or of 
-		 *							BansheeEngine.MissingComponent type if the original type is missing.
-		 * @param[in]	data		Serialized managed component data that will be used for initializing the new managed
-		 *							instance.
-		 * @param[in]	missingType	Is the component's type missing (can happen after assembly reload). If true then the
-		 *							serialized data will be stored internally until later date when user perhaps restores
-		 *							the type with another refresh. @p instance must be null if this is true.
-		 */
-		void restore(MonoObject* instance, const ComponentBackupData& data, bool missingType);
-
-		/**	Triggers the managed OnInitialize callback. */
-		void triggerOnInitialize();
-
-		/**	Triggers the managed OnReset callback. */
-		void triggerOnReset();
-
-	private:
-		/**
-		 * Finalizes construction of the object. Must be called before use or when the managed component instance changes.
-		 *
-		 * @param[in]	object	Managed component instance.
-		 */
-		void initialize(MonoObject* object);
-
-		typedef void(__stdcall *OnInitializedThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnUpdateThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnDestroyedThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnResetThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnEnabledThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnDisabledThunkDef) (MonoObject*, MonoException**);
-		typedef void(__stdcall *OnTransformChangedThunkDef) (MonoObject*, TransformChangedFlags, MonoException**);
-
-		MonoObject* mManagedInstance;
-		MonoReflectionType* mRuntimeType;
-		uint32_t mManagedHandle;
-
-		String mNamespace;
-		String mTypeName;
-		String mFullTypeName;
-		bool mRunInEditor;
-		bool mRequiresReset;
-
-		bool mMissingType;
-		ManagedSerializableObjectPtr mSerializedObjectData;
-		ManagedSerializableObjectInfoPtr mObjInfo; // Transient
-
-		OnInitializedThunkDef mOnInitializedThunk;
-		OnUpdateThunkDef mOnUpdateThunk;
-		OnResetThunkDef mOnResetThunk;
-		OnDestroyedThunkDef mOnDestroyThunk;
-		OnDestroyedThunkDef mOnDisabledThunk;
-		OnDestroyedThunkDef mOnEnabledThunk;
-		OnTransformChangedThunkDef mOnTransformChangedThunk;
-		MonoMethod* mCalculateBoundsMethod;
-
-		/************************************************************************/
-		/* 							COMPONENT OVERRIDES                    		*/
-		/************************************************************************/
-
-	protected:
-		friend class SceneObject;
-		friend class ScriptComponent;
-
-		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
-
-		/** @copydoc Component::instantiate */
-		void instantiate() override;
-
-		/** @copydoc Component::onInitialized */
-		void onInitialized() override;
-
-		/** @copydoc Component::onDestroyed */
-		void onDestroyed() override;
-
-		/** @copydoc Component::onEnabled  */
-		void onEnabled() override;
-
-		/** @copydoc Component::onDisabled  */
-		void onDisabled() override;
-
-		/** @copydoc Component::onTransformChanged  */
-		void onTransformChanged(TransformChangedFlags flags) override;
-
-	public:
-		/** @copydoc Component::update */
-		void update() override;
-
-		/** @copydoc Component::typeEquals */
-		bool typeEquals(const Component& other) override;
-
-		/** @copydoc Component::calculateBounds */
-		bool calculateBounds(Bounds& bounds) override;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class ManagedComponentRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-
-	protected:
-		ManagedComponent(); // Serialization only
-	};
-
-	/**	Contains serialized component data buffer. */
-	struct ComponentBackupData
-	{
-		UINT8* data;
-		UINT32 size;
-	};
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsComponent.h"
+#include <mono/jit/jit.h>
+
+namespace BansheeEngine
+{
+	struct ComponentBackupData;
+
+	/**
+	 * Component that internally wraps a managed component object that can be of user-defined type. Acts as interop interop
+	 * layer between native Component and a managed user defined component type since managed types cannot simply derive
+	 * from Component to implement its functionality.
+	 */
+	class BS_SCR_BE_EXPORT ManagedComponent : public Component
+	{
+	public:
+		~ManagedComponent();
+
+		/**	Returns managed component object instance. */
+		MonoObject* getManagedInstance() const { return mManagedInstance; }
+
+		/**	Returns managed type of the component. */
+		MonoReflectionType* getRuntimeType() const { return mRuntimeType; }
+
+		/**	Returns namespace of the managed component. */
+		const String& getManagedNamespace() const { return mNamespace; }
+
+		/**	Returns type name of the managed component. */
+		const String& getManagedTypeName() const { return mTypeName; }
+
+		/**	Returns namespace and type name of the component in format "namespace.typename". */
+		const String& getManagedFullTypeName() const { return mFullTypeName; }
+
+		/** Returns true if the component is allowed to run when the game is not playing .*/
+		bool runInEditor() const { return mRunInEditor; }
+
+		/**
+		 * Serializes the internal managed component.
+		 *
+		 * @param[in]	clearExisting	Should the managed component handle be released. (Will trigger a finalizer if this
+		 *								is the last reference to it)
+		 * @return						An object containing the serialized component. You can provide this to restore()
+		 *								method to re-create the original component.
+		 */
+		ComponentBackupData backup(bool clearExisting = true);
+
+		/**
+		 * Restores a component from previously serialized data.
+		 *
+		 * @param[in]	instance	New instance of the managed component. Must be of the valid component type or of 
+		 *							BansheeEngine.MissingComponent type if the original type is missing.
+		 * @param[in]	data		Serialized managed component data that will be used for initializing the new managed
+		 *							instance.
+		 * @param[in]	missingType	Is the component's type missing (can happen after assembly reload). If true then the
+		 *							serialized data will be stored internally until later date when user perhaps restores
+		 *							the type with another refresh. @p instance must be null if this is true.
+		 */
+		void restore(MonoObject* instance, const ComponentBackupData& data, bool missingType);
+
+		/**	Triggers the managed OnInitialize callback. */
+		void triggerOnInitialize();
+
+		/**	Triggers the managed OnReset callback. */
+		void triggerOnReset();
+
+		/**	Triggers the managed OnEnable callback. */
+		void triggerOnEnable();
+
+	private:
+		/**
+		 * Finalizes construction of the object. Must be called before use or when the managed component instance changes.
+		 *
+		 * @param[in]	object	Managed component instance.
+		 */
+		void initialize(MonoObject* object);
+
+		typedef void(__stdcall *OnInitializedThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnUpdateThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnDestroyedThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnResetThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnEnabledThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnDisabledThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnTransformChangedThunkDef) (MonoObject*, TransformChangedFlags, MonoException**);
+
+		MonoObject* mManagedInstance;
+		MonoReflectionType* mRuntimeType;
+		uint32_t mManagedHandle;
+
+		String mNamespace;
+		String mTypeName;
+		String mFullTypeName;
+		bool mRunInEditor;
+		bool mRequiresReset;
+
+		bool mMissingType;
+		ManagedSerializableObjectPtr mSerializedObjectData;
+		ManagedSerializableObjectInfoPtr mObjInfo; // Transient
+
+		OnInitializedThunkDef mOnInitializedThunk;
+		OnUpdateThunkDef mOnUpdateThunk;
+		OnResetThunkDef mOnResetThunk;
+		OnDestroyedThunkDef mOnDestroyThunk;
+		OnDestroyedThunkDef mOnDisabledThunk;
+		OnDestroyedThunkDef mOnEnabledThunk;
+		OnTransformChangedThunkDef mOnTransformChangedThunk;
+		MonoMethod* mCalculateBoundsMethod;
+
+		/************************************************************************/
+		/* 							COMPONENT OVERRIDES                    		*/
+		/************************************************************************/
+
+	protected:
+		friend class SceneObject;
+		friend class ScriptComponent;
+
+		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
+
+		/** @copydoc Component::instantiate */
+		void instantiate() override;
+
+		/** @copydoc Component::onInitialized */
+		void onInitialized() override;
+
+		/** @copydoc Component::onDestroyed */
+		void onDestroyed() override;
+
+		/** @copydoc Component::onEnabled  */
+		void onEnabled() override;
+
+		/** @copydoc Component::onDisabled  */
+		void onDisabled() override;
+
+		/** @copydoc Component::onTransformChanged  */
+		void onTransformChanged(TransformChangedFlags flags) override;
+
+	public:
+		/** @copydoc Component::update */
+		void update() override;
+
+		/** @copydoc Component::typeEquals */
+		bool typeEquals(const Component& other) override;
+
+		/** @copydoc Component::calculateBounds */
+		bool calculateBounds(Bounds& bounds) override;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ManagedComponentRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+
+	protected:
+		ManagedComponent(); // Serialization only
+	};
+
+	/**	Contains serialized component data buffer. */
+	struct ComponentBackupData
+	{
+		UINT8* data;
+		UINT32 size;
+	};
 }

+ 107 - 127
Source/SBansheeEngine/Include/BsScriptGameObjectManager.h

@@ -1,128 +1,108 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsScriptEnginePrerequisites.h"
-#include "BsModule.h"
-#include <mono/jit/jit.h>
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Manages all active GameObject interop objects. GameObjects can be created from native
-	 *			code and used in managed code therefore we need to keep a dictionary or all the native
-	 *			objects we have mapped to managed objects.
-	 */
-	class BS_SCR_BE_EXPORT ScriptGameObjectManager : public Module<ScriptGameObjectManager>
-	{
-		/**
-		 * @brief	Contains information about a single interop object containing a game object.
-		 */
-		struct ScriptGameObjectEntry
-		{
-			ScriptGameObjectEntry();
-			ScriptGameObjectEntry(ScriptGameObjectBase* instance, bool isComponent);
-
-			ScriptGameObjectBase* instance;
-			bool isComponent;
-		};
-
-	public:
-		ScriptGameObjectManager();
-		~ScriptGameObjectManager();
-
-		/**
-		 * @brief	Attempts to find the interop object for the specified SceneObject. If one cannot be found
-		 *			new one is created and returned.
-		 */
-		ScriptSceneObject* getOrCreateScriptSceneObject(const HSceneObject& sceneObject);
-
-		/**
-		 * @brief	Creates a new interop object for the specified SceneObject. Throws an exception if one
-		 *			already exists.
-		 */
-		ScriptSceneObject* createScriptSceneObject(const HSceneObject& sceneObject);
-
-		/**
-		 * @brief	Connects an existing managed SceneObject instance with the native SceneObject by creating
-		 *			the interop object. Throws an exception if the interop object already exists.
-		 */
-		ScriptSceneObject* createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject);
-
-		/**
-		 * @brief	Connects an existing managed ManagedComponent instance with the native ManagedComponent by creating
-		 *			the interop object. Throws an exception if the interop object already exists.
-		 */
-		ScriptComponent* createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component);
-
-		/**
-		 * @brief	Attempts to find the interop object for the specified managed component. 
-		 *			If one cannot be found null is returned.
-		 */
-		ScriptComponent* getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const;
-
-		/**
-		 * @brief	Attempts to find the interop object for a managed component with the specified instance ID. 
-		 *			If one cannot be found null is returned.
-		 */
-		ScriptComponent* getScriptComponent(UINT64 instanceId) const;
-
-		/**
-		 * @brief	Attempts to find the interop object for the specified SceneObject. If one cannot be found
-		 *			null is returned.
-		 */
-		ScriptSceneObject* getScriptSceneObject(const HSceneObject& sceneObject) const;
-
-		/**
-		 * @brief	Attempts to find the interop object for a managed scene object with the specified instance ID. 
-		 * 			If one cannot be found null is returned.
-		 */
-		ScriptSceneObject* getScriptSceneObject(UINT64 instanceId) const;
-
-		/**
-		 * @brief	Attempts to find the interop object for a GameObject with the specified instance ID. 
-		 *			If one cannot be found null is returned.
-		 */
-		ScriptGameObjectBase* getScriptGameObject(UINT64 instanceId) const;
-
-		/**
-		 * @brief	Notifies the managed that the OnInitialize method on a managed component has been called.
-		 */
-		void notifyComponentInitialized(UINT64 instanceId);
-
-		/**
-		 * @brief	Destroys and unregisters the specified SceneObject interop object.
-		 */
-		void destroyScriptSceneObject(ScriptSceneObject* sceneObject);
-
-		/**
-		 * @brief	Destroys and unregisters the specified ManagedComponent interop object.
-		 */
-		void destroyScriptComponent(ScriptComponent* component);
-
-		/**
-		 * @brief	Triggers OnInitialize methods on all uninitialized managed components.
-		 */
-		void sendComponentInitializeEvents();
-
-	private:
-		/**
-		 * @brief	Triggers OnReset methods on all registered managed components.
-		 *
-		 * @note	Usually this happens after an assembly reload.
-		 */
-		void sendComponentResetEvents();
-
-		/**
-		 * @brief	Triggered when the any game object is destroyed.
-		 */
-		void onGameObjectDestroyed(const HGameObject& go);
-
-		UnorderedMap<UINT64, ScriptComponent*> mScriptComponents;
-		UnorderedMap<UINT64, ScriptSceneObject*> mScriptSceneObjects;
-		UnorderedMap<UINT64, ScriptComponent*> mUninitializedScriptComponents;
-
-		HEvent mOnAssemblyReloadDoneConn;
-		HEvent onGameObjectDestroyedConn;
-	};
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsModule.h"
+#include <mono/jit/jit.h>
+
+namespace BansheeEngine
+{
+	/**
+	 * Manages all active GameObject interop objects. GameObjects can be created from native code and used in managed code
+	 * therefore we need to keep a dictionary or all the native objects we have mapped to managed objects.
+	 */
+	class BS_SCR_BE_EXPORT ScriptGameObjectManager : public Module<ScriptGameObjectManager>
+	{
+		/**	Contains information about a single interop object containing a game object. */
+		struct ScriptGameObjectEntry
+		{
+			ScriptGameObjectEntry();
+			ScriptGameObjectEntry(ScriptGameObjectBase* instance, bool isComponent);
+
+			ScriptGameObjectBase* instance;
+			bool isComponent;
+		};
+
+	public:
+		ScriptGameObjectManager();
+		~ScriptGameObjectManager();
+
+		/**
+		 * Attempts to find the interop object for the specified SceneObject. If one cannot be found new one is created and
+		 * returned.
+		 */
+		ScriptSceneObject* getOrCreateScriptSceneObject(const HSceneObject& sceneObject);
+
+		/** Creates a new interop object for the specified SceneObject. Throws an exception if one already exists. */
+		ScriptSceneObject* createScriptSceneObject(const HSceneObject& sceneObject);
+
+		/**
+		 * Connects an existing managed SceneObject instance with the native SceneObject by creating the interop object.
+		 * Throws an exception if the interop object already exists.
+		 */
+		ScriptSceneObject* createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject);
+
+		/**
+		 * Connects an existing managed ManagedComponent instance with the native ManagedComponent by creating the interop
+		 * object. Throws an exception if the interop object already exists.
+		 */
+		ScriptComponent* createScriptComponent(MonoObject* existingInstance, 
+			const GameObjectHandle<ManagedComponent>& component);
+
+		/**
+		 * Attempts to find the interop object for the specified managed component. If one cannot be found null is returned.
+		 */
+		ScriptComponent* getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const;
+
+		/**
+		 * Attempts to find the interop object for a managed component with the specified instance ID. If one cannot be
+		 * found null is returned.
+		 */
+		ScriptComponent* getScriptComponent(UINT64 instanceId) const;
+
+		/** Attempts to find the interop object for the specified SceneObject. If one cannot be found null is returned. */
+		ScriptSceneObject* getScriptSceneObject(const HSceneObject& sceneObject) const;
+
+		/**
+		 * Attempts to find the interop object for a managed scene object with the specified instance ID. If one cannot be
+		 * found null is returned.
+		 */
+		ScriptSceneObject* getScriptSceneObject(UINT64 instanceId) const;
+
+		/**
+		 * Attempts to find the interop object for a GameObject with the specified instance ID. If one cannot be found null
+		 * is returned.
+		 */
+		ScriptGameObjectBase* getScriptGameObject(UINT64 instanceId) const;
+
+		/**	Destroys and unregisters the specified SceneObject interop object. */
+		void destroyScriptSceneObject(ScriptSceneObject* sceneObject);
+
+		/**	Destroys and unregisters the specified ManagedComponent interop object. */
+		void destroyScriptComponent(ScriptComponent* component);
+
+		/** 
+		 * Sends OnInitialize/OnEnable events to all components that run only while the game is playing (i.e. without 
+		 * RunInEditor attribute). 
+		 */
+		void wakeRuntimeComponents();
+
+	private:
+		/**
+		 * Triggers OnReset methods on all registered managed components.
+		 *
+		 * @note	Usually this happens after an assembly reload.
+		 */
+		void sendComponentResetEvents();
+
+		/**	Triggered when the any game object is destroyed. */
+		void onGameObjectDestroyed(const HGameObject& go);
+
+		UnorderedMap<UINT64, ScriptComponent*> mScriptComponents;
+		UnorderedMap<UINT64, ScriptSceneObject*> mScriptSceneObjects;
+
+		HEvent mOnAssemblyReloadDoneConn;
+		HEvent onGameObjectDestroyedConn;
+	};
 }

+ 428 - 393
Source/SBansheeEngine/Source/BsManagedComponent.cpp

@@ -1,394 +1,429 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsManagedComponent.h"
-#include "BsManagedComponentRTTI.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
-#include "BsMonoUtil.h"
-#include "BsMonoMethod.h"
-#include "BsMemorySerializer.h"
-#include "BsManagedSerializableObject.h"
-#include "BsScriptGameObjectManager.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsMonoAssembly.h"
-#include "BsPlayInEditorManager.h"
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	ManagedComponent::ManagedComponent()
-		:mManagedInstance(nullptr), mOnUpdateThunk(nullptr), mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), 
-		mOnResetThunk(nullptr), mMissingType(false), mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr),
-		mOnTransformChangedThunk(nullptr), mCalculateBoundsMethod(nullptr), mRunInEditor(false)
-	{ }
-
-	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
-		: Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType), mOnUpdateThunk(nullptr), 
-		mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), mOnResetThunk(nullptr), mMissingType(false), 
-		mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr), mCalculateBoundsMethod(nullptr),
-		mOnTransformChangedThunk(nullptr), mRunInEditor(false)
-	{
-		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
-		::MonoClass* monoClass = mono_type_get_class(monoType);
-
-		MonoUtil::getClassName(monoClass, mNamespace, mTypeName);
-		setName(mTypeName);
-	}
-
-	ManagedComponent::~ManagedComponent()
-	{
-
-	}
-
-	ComponentBackupData ManagedComponent::backup(bool clearExisting)
-	{
-		ComponentBackupData backupData;
-
-		// If type is not missing read data from actual managed instance, instead just 
-		// return the data we backed up before the type was lost
-		if (!mMissingType)
-		{
-			ManagedSerializableObjectPtr serializableObject = ManagedSerializableObject::createFromExisting(mManagedInstance);
-
-			// Serialize the object information and its fields. We cannot just serialize the entire object because
-			// the managed instance had to be created in a previous step. So we handle creation of the top level object manually.
-			
-			if (serializableObject != nullptr)
-			{
-				MemorySerializer ms;
-
-				backupData.size = 0;
-				backupData.data = ms.encode(serializableObject.get(), backupData.size);
-			}
-			else
-			{
-				backupData.size = 0;
-				backupData.data = nullptr;
-			}
-		}
-		else
-		{
-			MemorySerializer ms;
-
-			backupData.size = 0;
-
-			if (mSerializedObjectData != nullptr)
-				backupData.data = ms.encode(mSerializedObjectData.get(), backupData.size);
-			else
-				backupData.data = nullptr;
-		}
-
-		if (clearExisting)
-		{
-			if (mManagedInstance != nullptr)
-			{
-				mManagedInstance = nullptr;
-				mono_gchandle_free(mManagedHandle);
-				mManagedHandle = 0;
-			}
-
-			mRuntimeType = nullptr;
-			mOnInitializedThunk = nullptr;
-			mOnUpdateThunk = nullptr;
-			mOnDestroyThunk = nullptr;
-			mOnEnabledThunk = nullptr;
-			mOnDisabledThunk = nullptr;
-			mOnTransformChangedThunk = nullptr;
-			mCalculateBoundsMethod = nullptr;
-		}
-
-		return backupData;
-	}
-
-	void ManagedComponent::restore(MonoObject* instance, const ComponentBackupData& data, bool missingType)
-	{
-		initialize(instance);
-		mObjInfo = nullptr;
-
-		if (instance != nullptr && data.data != nullptr)
-		{
-			MemorySerializer ms;
-
-			GameObjectManager::instance().startDeserialization();
-			ManagedSerializableObjectPtr serializableObject = std::static_pointer_cast<ManagedSerializableObject>(ms.decode(data.data, data.size));
-			GameObjectManager::instance().endDeserialization();
-
-			if (!missingType)
-			{
-				ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo);
-
-				serializableObject->deserialize(instance, mObjInfo);
-			}
-			else
-				mSerializedObjectData = serializableObject;
-		}
-
-		if (!missingType)
-			mSerializedObjectData = nullptr;
-
-		mMissingType = missingType;
-		mRequiresReset = true;
-	}
-
-	void ManagedComponent::initialize(MonoObject* object)
-	{
-		mFullTypeName = mNamespace + "." + mTypeName;
-		mManagedInstance = object;
-		
-		MonoClass* managedClass = nullptr;
-		if (mManagedInstance != nullptr)
-		{
-			mManagedHandle = mono_gchandle_new(mManagedInstance, false);
-
-			::MonoClass* monoClass = mono_object_get_class(object);
-			MonoType* monoType = mono_class_get_type(monoClass);
-			mRuntimeType = mono_type_get_object(MonoManager::instance().getDomain(), monoType);
-
-			managedClass = MonoManager::instance().findClass(monoClass);
-		}
-
-		if (managedClass != nullptr)
-		{
-			MonoMethod* onInitializedMethod = managedClass->getMethod("OnInitialize", 0);
-			if (onInitializedMethod != nullptr)
-				mOnInitializedThunk = (OnInitializedThunkDef)onInitializedMethod->getThunk();
-
-			MonoMethod* onUpdateMethod = managedClass->getMethod("OnUpdate", 0);
-			if (onUpdateMethod != nullptr)
-				mOnUpdateThunk = (OnUpdateThunkDef)onUpdateMethod->getThunk();
-
-			MonoMethod* onResetMethod = managedClass->getMethod("OnReset", 0);
-			if (onResetMethod != nullptr)
-				mOnResetThunk = (OnResetThunkDef)onResetMethod->getThunk();
-
-			MonoMethod* onDestroyMethod = managedClass->getMethod("OnDestroy", 0);
-			if (onDestroyMethod != nullptr)
-				mOnDestroyThunk = (OnDestroyedThunkDef)onDestroyMethod->getThunk();
-
-			MonoMethod* onDisableMethod = managedClass->getMethod("OnDisable", 0);
-			if (onDisableMethod != nullptr)
-				mOnDisabledThunk = (OnDisabledThunkDef)onDisableMethod->getThunk();
-
-			MonoMethod* onEnableMethod = managedClass->getMethod("OnEnable", 0);
-			if (onEnableMethod != nullptr)
-				mOnEnabledThunk = (OnInitializedThunkDef)onEnableMethod->getThunk();
-
-			MonoMethod* onTransformChangedMethod = managedClass->getMethod("OnTransformChanged", 1);
-			if (onTransformChangedMethod != nullptr)
-				mOnTransformChangedThunk = (OnTransformChangedThunkDef)onTransformChangedMethod->getThunk();
-
-			mCalculateBoundsMethod = managedClass->getMethod("CalculateBounds", 2);
-
-			MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);
-			if (bansheeEngineAssembly == nullptr)
-				BS_EXCEPT(InvalidStateException, String(ENGINE_ASSEMBLY) + " assembly is not loaded.");
-
-			MonoClass* runInEditorAttrib = bansheeEngineAssembly->getClass("BansheeEngine", "RunInEditor");
-			if (runInEditorAttrib == nullptr)
-				BS_EXCEPT(InvalidStateException, "Cannot find RunInEditor managed class.");
-
-			mRunInEditor = managedClass->getAttribute(runInEditorAttrib) != nullptr;
-		}
-		else
-			mRunInEditor = false;
-	}
-
-	bool ManagedComponent::typeEquals(const Component& other)
-	{
-		if(Component::typeEquals(other))
-		{
-			const ManagedComponent& otherMC = static_cast<const ManagedComponent&>(other);
-
-			// Not comparing MonoReflectionType directly because this needs to be able to work before instantiation
-			return mNamespace == otherMC.getManagedNamespace() && mTypeName == otherMC.getManagedTypeName();
-		}
-
-		return false;
-	}
-
-	bool ManagedComponent::calculateBounds(Bounds& bounds)
-	{
-		if (mManagedInstance != nullptr && mCalculateBoundsMethod != nullptr)
-		{
-			AABox box;
-			Sphere sphere;
-
-			void* params[2];
-			params[0] = &box;
-			params[1] = &sphere;
-
-			MonoObject* areBoundsValidObj = mCalculateBoundsMethod->invokeVirtual(mManagedInstance, params);
-
-			bool areBoundsValid;
-			areBoundsValid = *(bool*)mono_object_unbox(areBoundsValidObj);
-
-			bounds = Bounds(box, sphere);
-			return areBoundsValid;
-		}
-
-		return Component::calculateBounds(bounds);
-	}
-
-	void ManagedComponent::update()
-	{
-		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing && !mRunInEditor)
-			return;
-
-		assert(mManagedInstance != nullptr);
-
-		if (mOnUpdateThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnUpdateThunk, mManagedInstance);
-		}
-	}
-
-	void ManagedComponent::triggerOnInitialize()
-	{
-		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Playing || mRunInEditor)
-		{
-			if (mOnInitializedThunk != nullptr)
-			{
-				// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-				// for some extra speed.
-				MonoUtil::invokeThunk(mOnInitializedThunk, mManagedInstance);
-			}
-
-			ScriptGameObjectManager::instance().notifyComponentInitialized(getInstanceId());
-		}
-	}
-
-	void ManagedComponent::triggerOnReset()
-	{
-		assert(mManagedInstance != nullptr);
-
-		if (mRequiresReset && mOnResetThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnResetThunk, mManagedInstance);
-		}
-
-		mRequiresReset = false;
-	}
-
-	void ManagedComponent::instantiate()
-	{
-		mObjInfo = nullptr;
-		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo))
-		{
-			MonoObject* instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
-
-			initialize(instance);
-			mMissingType = true;
-		}
-		else
-		{
-			initialize(mObjInfo->mMonoClass->createInstance());
-			mMissingType = false;
-		}
-
-		assert(mManagedInstance != nullptr);
-
-		// Find handle to self
-		HManagedComponent componentHandle;
-		if (SO() != nullptr)
-		{
-			const Vector<HComponent>& components = SO()->getComponents();
-			for (auto& component : components)
-			{
-				if (component.get() == this)
-				{
-					componentHandle = component;
-					break;
-				}
-			}
-		}
-
-		assert(componentHandle != nullptr);
-		ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(mManagedInstance, componentHandle);
-	}
-
-	void ManagedComponent::onInitialized()
-	{
-		assert(mManagedInstance != nullptr);
-
-		if (mSerializedObjectData != nullptr && !mMissingType)
-		{
-			mSerializedObjectData->deserialize(mManagedInstance, mObjInfo);
-			mSerializedObjectData = nullptr;
-		}
-
-		triggerOnInitialize();
-		triggerOnReset();
-	}
-
-	void ManagedComponent::onDestroyed()
-	{
-		assert(mManagedInstance != nullptr);
-
-		if (mOnDestroyThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
-		}
-
-		mManagedInstance = nullptr;
-		mono_gchandle_free(mManagedHandle);
-	}
-
-	void ManagedComponent::onEnabled()
-	{
-		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
-			return;
-
-		assert(mManagedInstance != nullptr);
-
-		if (mOnEnabledThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnEnabledThunk, mManagedInstance);
-		}
-	}
-
-	void ManagedComponent::onDisabled()
-	{
-		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
-			return;
-
-		assert(mManagedInstance != nullptr);
-
-		if (mOnDisabledThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnDisabledThunk, mManagedInstance);
-		}
-	}
-
-	void ManagedComponent::onTransformChanged(TransformChangedFlags flags)
-	{
-		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
-			return;
-
-		if(mOnTransformChangedThunk != nullptr)
-		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnTransformChangedThunk, mManagedInstance, flags);
-		}
-	}
-
-	RTTITypeBase* ManagedComponent::getRTTIStatic()
-	{
-		return ManagedComponentRTTI::instance();
-	}
-
-	RTTITypeBase* ManagedComponent::getRTTI() const
-	{
-		return ManagedComponent::getRTTIStatic();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsManagedComponent.h"
+#include "BsManagedComponentRTTI.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+#include "BsMonoMethod.h"
+#include "BsMemorySerializer.h"
+#include "BsManagedSerializableObject.h"
+#include "BsScriptGameObjectManager.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsMonoAssembly.h"
+#include "BsPlayInEditorManager.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	ManagedComponent::ManagedComponent()
+		:mManagedInstance(nullptr), mOnUpdateThunk(nullptr), mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), 
+		mOnResetThunk(nullptr), mMissingType(false), mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr),
+		mOnTransformChangedThunk(nullptr), mCalculateBoundsMethod(nullptr), mRunInEditor(false)
+	{ }
+
+	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
+		: Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType), mOnUpdateThunk(nullptr), 
+		mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), mOnResetThunk(nullptr), mMissingType(false), 
+		mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr), mCalculateBoundsMethod(nullptr),
+		mOnTransformChangedThunk(nullptr), mRunInEditor(false)
+	{
+		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
+		::MonoClass* monoClass = mono_type_get_class(monoType);
+
+		MonoUtil::getClassName(monoClass, mNamespace, mTypeName);
+		setName(mTypeName);
+	}
+
+	ManagedComponent::~ManagedComponent()
+	{
+
+	}
+
+	ComponentBackupData ManagedComponent::backup(bool clearExisting)
+	{
+		ComponentBackupData backupData;
+
+		// If type is not missing read data from actual managed instance, instead just 
+		// return the data we backed up before the type was lost
+		if (!mMissingType)
+		{
+			ManagedSerializableObjectPtr serializableObject = ManagedSerializableObject::createFromExisting(mManagedInstance);
+
+			// Serialize the object information and its fields. We cannot just serialize the entire object because
+			// the managed instance had to be created in a previous step. So we handle creation of the top level object manually.
+			
+			if (serializableObject != nullptr)
+			{
+				MemorySerializer ms;
+
+				backupData.size = 0;
+				backupData.data = ms.encode(serializableObject.get(), backupData.size);
+			}
+			else
+			{
+				backupData.size = 0;
+				backupData.data = nullptr;
+			}
+		}
+		else
+		{
+			MemorySerializer ms;
+
+			backupData.size = 0;
+
+			if (mSerializedObjectData != nullptr)
+				backupData.data = ms.encode(mSerializedObjectData.get(), backupData.size);
+			else
+				backupData.data = nullptr;
+		}
+
+		if (clearExisting)
+		{
+			if (mManagedInstance != nullptr)
+			{
+				mManagedInstance = nullptr;
+				mono_gchandle_free(mManagedHandle);
+				mManagedHandle = 0;
+			}
+
+			mRuntimeType = nullptr;
+			mOnInitializedThunk = nullptr;
+			mOnUpdateThunk = nullptr;
+			mOnDestroyThunk = nullptr;
+			mOnEnabledThunk = nullptr;
+			mOnDisabledThunk = nullptr;
+			mOnTransformChangedThunk = nullptr;
+			mCalculateBoundsMethod = nullptr;
+		}
+
+		return backupData;
+	}
+
+	void ManagedComponent::restore(MonoObject* instance, const ComponentBackupData& data, bool missingType)
+	{
+		initialize(instance);
+		mObjInfo = nullptr;
+
+		if (instance != nullptr && data.data != nullptr)
+		{
+			MemorySerializer ms;
+
+			GameObjectManager::instance().startDeserialization();
+			ManagedSerializableObjectPtr serializableObject = std::static_pointer_cast<ManagedSerializableObject>(ms.decode(data.data, data.size));
+			GameObjectManager::instance().endDeserialization();
+
+			if (!missingType)
+			{
+				ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo);
+
+				serializableObject->deserialize(instance, mObjInfo);
+			}
+			else
+				mSerializedObjectData = serializableObject;
+		}
+
+		if (!missingType)
+			mSerializedObjectData = nullptr;
+
+		mMissingType = missingType;
+		mRequiresReset = true;
+	}
+
+	void ManagedComponent::initialize(MonoObject* object)
+	{
+		mFullTypeName = mNamespace + "." + mTypeName;
+		mManagedInstance = object;
+		
+		MonoClass* managedClass = nullptr;
+		if (mManagedInstance != nullptr)
+		{
+			mManagedHandle = mono_gchandle_new(mManagedInstance, false);
+
+			::MonoClass* monoClass = mono_object_get_class(object);
+			MonoType* monoType = mono_class_get_type(monoClass);
+			mRuntimeType = mono_type_get_object(MonoManager::instance().getDomain(), monoType);
+
+			managedClass = MonoManager::instance().findClass(monoClass);
+		}
+
+		while(managedClass != nullptr)
+		{
+			if (mOnInitializedThunk == nullptr)
+			{
+				MonoMethod* onInitializedMethod = managedClass->getMethod("OnInitialize", 0);
+				if (onInitializedMethod != nullptr)
+					mOnInitializedThunk = (OnInitializedThunkDef)onInitializedMethod->getThunk();
+			}
+
+			if (mOnUpdateThunk == nullptr)
+			{
+				MonoMethod* onUpdateMethod = managedClass->getMethod("OnUpdate", 0);
+				if (onUpdateMethod != nullptr)
+					mOnUpdateThunk = (OnUpdateThunkDef)onUpdateMethod->getThunk();
+			}
+
+			if (mOnResetThunk == nullptr)
+			{
+				MonoMethod* onResetMethod = managedClass->getMethod("OnReset", 0);
+				if (onResetMethod != nullptr)
+					mOnResetThunk = (OnResetThunkDef)onResetMethod->getThunk();
+			}
+
+			if (mOnDestroyThunk == nullptr)
+			{
+				MonoMethod* onDestroyMethod = managedClass->getMethod("OnDestroy", 0);
+				if (onDestroyMethod != nullptr)
+					mOnDestroyThunk = (OnDestroyedThunkDef)onDestroyMethod->getThunk();
+			}
+
+			if (mOnDisabledThunk == nullptr)
+			{
+				MonoMethod* onDisableMethod = managedClass->getMethod("OnDisable", 0);
+				if (onDisableMethod != nullptr)
+					mOnDisabledThunk = (OnDisabledThunkDef)onDisableMethod->getThunk();
+			}
+
+			if (mOnEnabledThunk == nullptr)
+			{
+				MonoMethod* onEnableMethod = managedClass->getMethod("OnEnable", 0);
+				if (onEnableMethod != nullptr)
+					mOnEnabledThunk = (OnInitializedThunkDef)onEnableMethod->getThunk();
+			}
+
+			if (mOnTransformChangedThunk == nullptr)
+			{
+				MonoMethod* onTransformChangedMethod = managedClass->getMethod("OnTransformChanged", 1);
+				if (onTransformChangedMethod != nullptr)
+					mOnTransformChangedThunk = (OnTransformChangedThunkDef)onTransformChangedMethod->getThunk();
+			}
+
+			if(mCalculateBoundsMethod == nullptr)
+				mCalculateBoundsMethod = managedClass->getMethod("CalculateBounds", 2);
+
+			// Search for methods on base class if there is one
+			MonoClass* baseClass = managedClass->getBaseClass();
+			if (baseClass != ScriptComponent::getMetaData()->scriptClass)
+				managedClass = baseClass;
+			else
+				break;
+		}
+
+		if (managedClass != nullptr)
+		{
+			MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);
+			if (bansheeEngineAssembly == nullptr)
+				BS_EXCEPT(InvalidStateException, String(ENGINE_ASSEMBLY) + " assembly is not loaded.");
+
+			MonoClass* runInEditorAttrib = bansheeEngineAssembly->getClass("BansheeEngine", "RunInEditor");
+			if (runInEditorAttrib == nullptr)
+				BS_EXCEPT(InvalidStateException, "Cannot find RunInEditor managed class.");
+
+			mRunInEditor = managedClass->getAttribute(runInEditorAttrib) != nullptr;
+		}
+		else
+			mRunInEditor = false;
+	}
+
+	bool ManagedComponent::typeEquals(const Component& other)
+	{
+		if(Component::typeEquals(other))
+		{
+			const ManagedComponent& otherMC = static_cast<const ManagedComponent&>(other);
+
+			// Not comparing MonoReflectionType directly because this needs to be able to work before instantiation
+			return mNamespace == otherMC.getManagedNamespace() && mTypeName == otherMC.getManagedTypeName();
+		}
+
+		return false;
+	}
+
+	bool ManagedComponent::calculateBounds(Bounds& bounds)
+	{
+		if (mManagedInstance != nullptr && mCalculateBoundsMethod != nullptr)
+		{
+			AABox box;
+			Sphere sphere;
+
+			void* params[2];
+			params[0] = &box;
+			params[1] = &sphere;
+
+			MonoObject* areBoundsValidObj = mCalculateBoundsMethod->invokeVirtual(mManagedInstance, params);
+
+			bool areBoundsValid;
+			areBoundsValid = *(bool*)mono_object_unbox(areBoundsValidObj);
+
+			bounds = Bounds(box, sphere);
+			return areBoundsValid;
+		}
+
+		return Component::calculateBounds(bounds);
+	}
+
+	void ManagedComponent::update()
+	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing && !mRunInEditor)
+			return;
+
+		assert(mManagedInstance != nullptr);
+
+		if (mOnUpdateThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnUpdateThunk, mManagedInstance);
+		}
+	}
+
+	void ManagedComponent::triggerOnInitialize()
+	{
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
+			return;
+
+		if (mOnInitializedThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnInitializedThunk, mManagedInstance);
+		}
+	}
+
+	void ManagedComponent::triggerOnReset()
+	{
+		assert(mManagedInstance != nullptr);
+
+		if (mRequiresReset && mOnResetThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnResetThunk, mManagedInstance);
+		}
+
+		mRequiresReset = false;
+	}
+
+	void ManagedComponent::triggerOnEnable()
+	{
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
+			return;
+
+		assert(mManagedInstance != nullptr);
+
+		if (mOnEnabledThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnEnabledThunk, mManagedInstance);
+		}
+	}
+
+	void ManagedComponent::instantiate()
+	{
+		mObjInfo = nullptr;
+		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo))
+		{
+			MonoObject* instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
+
+			initialize(instance);
+			mMissingType = true;
+		}
+		else
+		{
+			initialize(mObjInfo->mMonoClass->createInstance());
+			mMissingType = false;
+		}
+
+		assert(mManagedInstance != nullptr);
+
+		// Find handle to self
+		HManagedComponent componentHandle;
+		if (SO() != nullptr)
+		{
+			const Vector<HComponent>& components = SO()->getComponents();
+			for (auto& component : components)
+			{
+				if (component.get() == this)
+				{
+					componentHandle = component;
+					break;
+				}
+			}
+		}
+
+		assert(componentHandle != nullptr);
+		ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(mManagedInstance, componentHandle);
+	}
+
+	void ManagedComponent::onInitialized()
+	{
+		assert(mManagedInstance != nullptr);
+
+		if (mSerializedObjectData != nullptr && !mMissingType)
+		{
+			mSerializedObjectData->deserialize(mManagedInstance, mObjInfo);
+			mSerializedObjectData = nullptr;
+		}
+
+		triggerOnInitialize();
+		triggerOnReset();
+	}
+
+	void ManagedComponent::onDestroyed()
+	{
+		assert(mManagedInstance != nullptr);
+
+		if (mOnDestroyThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
+		}
+
+		mManagedInstance = nullptr;
+		mono_gchandle_free(mManagedHandle);
+	}
+
+	void ManagedComponent::onEnabled()
+	{
+		triggerOnEnable();
+	}
+
+	void ManagedComponent::onDisabled()
+	{
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
+			return;
+
+		assert(mManagedInstance != nullptr);
+
+		if (mOnDisabledThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnDisabledThunk, mManagedInstance);
+		}
+	}
+
+	void ManagedComponent::onTransformChanged(TransformChangedFlags flags)
+	{
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Stopped && !mRunInEditor)
+			return;
+
+		if(mOnTransformChangedThunk != nullptr)
+		{
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			MonoUtil::invokeThunk(mOnTransformChangedThunk, mManagedInstance, flags);
+		}
+	}
+
+	RTTITypeBase* ManagedComponent::getRTTIStatic()
+	{
+		return ManagedComponentRTTI::instance();
+	}
+
+	RTTITypeBase* ManagedComponent::getRTTI() const
+	{
+		return ManagedComponent::getRTTIStatic();
+	}
 }

+ 131 - 135
Source/SBansheeEngine/Source/BsPlayInEditorManager.cpp

@@ -1,136 +1,132 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPlayInEditorManager.h"
-#include "BsScriptGameObjectManager.h"
-#include "BsTime.h"
-#include "BsSceneManager.h"
-#include "BsSceneObject.h"
-#include "BsApplication.h"
-
-namespace BansheeEngine
-{
-	PlayInEditorManager::PlayInEditorManager()
-		:mState(PlayInEditorState::Stopped), mNextState(PlayInEditorState::Stopped), 
-		mFrameStepActive(false), mScheduledStateChange(false), mPausableTime(0.0f)
-	{
-		if (!gApplication().isEditor())
-			mState = PlayInEditorState::Playing;
-	}
-
-	void PlayInEditorManager::setState(PlayInEditorState state)
-	{
-		if (!gApplication().isEditor())
-			return;
-
-		// Delay state change to next frame as this method could be called in middle of object update, in which case
-		// part of the objects before this call would receive different state than other objects.
-		mScheduledStateChange = true;
-		mNextState = state;
-	}
-
-	void PlayInEditorManager::setStateImmediate(PlayInEditorState state)
-	{
-		if (mState == state)
-			return;
-
-		PlayInEditorState oldState = mState;
-		mState = state;
-
-		switch (state)
-		{
-		case PlayInEditorState::Stopped:
-		{
-			mFrameStepActive = false;
-			mPausableTime = 0.0f;
-
-			mSavedScene->_instantiate();
-			gSceneManager()._setRootNode(mSavedScene);
-			mSavedScene = nullptr;
-		}
-			break;
-		case PlayInEditorState::Playing:
-		{
-			if (oldState == PlayInEditorState::Paused)
-			{
-				ScriptGameObjectManager::instance().sendComponentInitializeEvents();
-			}
-			else // Was stopped
-			{
-				saveSceneInMemory();
-				ScriptGameObjectManager::instance().sendComponentInitializeEvents();
-			}
-		}
-			break;
-		case PlayInEditorState::Paused:
-		{
-			mFrameStepActive = false;
-			if (oldState == PlayInEditorState::Stopped)
-			{
-				saveSceneInMemory();
-				ScriptGameObjectManager::instance().sendComponentInitializeEvents();
-			}
-		}
-			break;
-		default:
-			break;
-		}		
-	}
-
-	void PlayInEditorManager::frameStep()
-	{
-		if (!gApplication().isEditor())
-			return;
-
-		switch (mState)
-		{
-		case PlayInEditorState::Stopped:
-		case PlayInEditorState::Paused:
-			setState(PlayInEditorState::Playing);
-			break;
-		}
-
-		mFrameStepActive = true;
-	}
-
-	void PlayInEditorManager::update()
-	{
-		if (mState == PlayInEditorState::Playing)
-			mPausableTime += gTime().getFrameDelta();
-
-		if (mScheduledStateChange)
-		{
-			setStateImmediate(mNextState);
-			mScheduledStateChange = false;
-		}
-
-		if (mFrameStepActive)
-		{
-			setState(PlayInEditorState::Paused);
-			mFrameStepActive = false;
-		}
-	}
-
-	void PlayInEditorManager::saveSceneInMemory()
-	{
-		mSavedScene = SceneManager::instance().getRootNode()->clone(false);
-
-		// Remove objects with "dont save" flag
-		Stack<HSceneObject> todo;
-		todo.push(mSavedScene);
-
-		while (!todo.empty())
-		{
-			HSceneObject current = todo.top();
-			todo.pop();
-
-			if (current->hasFlag(SOF_DontSave))
-				current->destroy();
-			else
-			{
-				UINT32 numChildren = current->getNumChildren();
-				for (UINT32 i = 0; i < numChildren; i++)
-					todo.push(current->getChild(i));
-			}
-		}
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPlayInEditorManager.h"
+#include "BsScriptGameObjectManager.h"
+#include "BsTime.h"
+#include "BsSceneManager.h"
+#include "BsSceneObject.h"
+#include "BsApplication.h"
+
+namespace BansheeEngine
+{
+	PlayInEditorManager::PlayInEditorManager()
+		:mState(PlayInEditorState::Stopped), mNextState(PlayInEditorState::Stopped), 
+		mFrameStepActive(false), mScheduledStateChange(false), mPausableTime(0.0f)
+	{
+		if (!gApplication().isEditor())
+			mState = PlayInEditorState::Playing;
+	}
+
+	void PlayInEditorManager::setState(PlayInEditorState state)
+	{
+		if (!gApplication().isEditor())
+			return;
+
+		// Delay state change to next frame as this method could be called in middle of object update, in which case
+		// part of the objects before this call would receive different state than other objects.
+		mScheduledStateChange = true;
+		mNextState = state;
+	}
+
+	void PlayInEditorManager::setStateImmediate(PlayInEditorState state)
+	{
+		if (mState == state)
+			return;
+
+		PlayInEditorState oldState = mState;
+		mState = state;
+
+		switch (state)
+		{
+		case PlayInEditorState::Stopped:
+		{
+			mFrameStepActive = false;
+			mPausableTime = 0.0f;
+
+			mSavedScene->_instantiate();
+			gSceneManager()._setRootNode(mSavedScene);
+			mSavedScene = nullptr;
+		}
+			break;
+		case PlayInEditorState::Playing:
+		{
+			if (oldState == PlayInEditorState::Stopped)
+			{
+				saveSceneInMemory();
+				ScriptGameObjectManager::instance().wakeRuntimeComponents();
+			}
+		}
+			break;
+		case PlayInEditorState::Paused:
+		{
+			mFrameStepActive = false;
+			if (oldState == PlayInEditorState::Stopped)
+			{
+				saveSceneInMemory();
+				ScriptGameObjectManager::instance().wakeRuntimeComponents();
+			}
+		}
+			break;
+		default:
+			break;
+		}		
+	}
+
+	void PlayInEditorManager::frameStep()
+	{
+		if (!gApplication().isEditor())
+			return;
+
+		switch (mState)
+		{
+		case PlayInEditorState::Stopped:
+		case PlayInEditorState::Paused:
+			setState(PlayInEditorState::Playing);
+			break;
+		}
+
+		mFrameStepActive = true;
+	}
+
+	void PlayInEditorManager::update()
+	{
+		if (mState == PlayInEditorState::Playing)
+			mPausableTime += gTime().getFrameDelta();
+
+		if (mScheduledStateChange)
+		{
+			setStateImmediate(mNextState);
+			mScheduledStateChange = false;
+		}
+
+		if (mFrameStepActive)
+		{
+			setState(PlayInEditorState::Paused);
+			mFrameStepActive = false;
+		}
+	}
+
+	void PlayInEditorManager::saveSceneInMemory()
+	{
+		mSavedScene = SceneManager::instance().getRootNode()->clone(false);
+
+		// Remove objects with "dont save" flag
+		Stack<HSceneObject> todo;
+		todo.push(mSavedScene);
+
+		while (!todo.empty())
+		{
+			HSceneObject current = todo.top();
+			todo.pop();
+
+			if (current->hasFlag(SOF_DontSave))
+				current->destroy();
+			else
+			{
+				UINT32 numChildren = current->getNumChildren();
+				for (UINT32 i = 0; i < numChildren; i++)
+					todo.push(current->getChild(i));
+			}
+		}
+	}
 }

+ 194 - 200
Source/SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -1,201 +1,195 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsScriptGameObjectManager.h"
-#include "BsScriptGameObject.h"
-#include "BsScriptComponent.h"
-#include "BsScriptSceneObject.h"
-#include "BsGameObjectManager.h"
-#include "BsGameObject.h"
-#include "BsComponent.h"
-#include "BsManagedComponent.h"
-#include "BsSceneObject.h"
-#include "BsMonoManager.h"
-#include "BsMonoAssembly.h"
-#include "BsMonoClass.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsScriptObjectManager.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	ScriptGameObjectManager::ScriptGameObjectEntry::ScriptGameObjectEntry()
-		:instance(nullptr), isComponent(false)
-	{ }
-
-	ScriptGameObjectManager::ScriptGameObjectEntry::ScriptGameObjectEntry(ScriptGameObjectBase* instance, bool isComponent)
-		:instance(instance), isComponent(isComponent)
-	{ }
-
-	ScriptGameObjectManager::ScriptGameObjectManager()
-	{
-		// Calls OnReset on all components after assembly reload happens
-		mOnAssemblyReloadDoneConn = ScriptObjectManager::instance().onRefreshComplete.connect(
-			std::bind(&ScriptGameObjectManager::sendComponentResetEvents, this));
-
-		onGameObjectDestroyedConn = GameObjectManager::instance().onDestroyed.connect(
-			std::bind(&ScriptGameObjectManager::onGameObjectDestroyed, this, _1));
-	}
-
-	ScriptGameObjectManager::~ScriptGameObjectManager()
-	{
-		mOnAssemblyReloadDoneConn.disconnect();
-		onGameObjectDestroyedConn.disconnect();
-	}
-
-	ScriptSceneObject* ScriptGameObjectManager::getOrCreateScriptSceneObject(const HSceneObject& sceneObject)
-	{
-		ScriptSceneObject* so = getScriptSceneObject(sceneObject);
-		if (so != nullptr)
-			return so;
-
-		return createScriptSceneObject(sceneObject);
-	}
-
-	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(const HSceneObject& sceneObject)
-	{
-		MonoClass* sceneObjectClass = ScriptAssemblyManager::instance().getSceneObjectClass();
-		MonoObject* instance = sceneObjectClass->createInstance();
-
-		return createScriptSceneObject(instance, sceneObject);
-	}
-
-	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject)
-	{
-		ScriptSceneObject* so = getScriptSceneObject(sceneObject);
-		if (so != nullptr)
-			BS_EXCEPT(InvalidStateException, "Script object for this SceneObject already exists.");
-
-		ScriptSceneObject* nativeInstance = new (bs_alloc<ScriptSceneObject>()) ScriptSceneObject(existingInstance, sceneObject);
-		mScriptSceneObjects[sceneObject.getInstanceId()] = nativeInstance;
-
-		return nativeInstance;
-	}
-
-	ScriptComponent* ScriptGameObjectManager::createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component)
-	{
-		ScriptGameObjectBase* comp = getScriptComponent(component.getInstanceId());
-		if (comp != nullptr)
-			BS_EXCEPT(InvalidStateException, "Script object for this Component already exists.");
-
-		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(existingInstance);
-		nativeInstance->setNativeHandle(component);
-
-		UINT64 instanceId = component->getInstanceId();
-		mScriptComponents[instanceId] = nativeInstance;
-		mUninitializedScriptComponents[instanceId] = nativeInstance;
-
-		return nativeInstance;
-	}
-
-	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
-	{
-		auto findIter = mScriptComponents.find(component.getInstanceId());
-		if (findIter != mScriptComponents.end())
-			return findIter->second;
-
-		return nullptr;
-	}
-
-	ScriptComponent* ScriptGameObjectManager::getScriptComponent(UINT64 instanceId) const
-	{
-		auto findIter = mScriptComponents.find(instanceId);
-		if (findIter != mScriptComponents.end())
-			return findIter->second;
-
-		return nullptr;
-	}
-
-	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(const HSceneObject& sceneObject) const
-	{
-		auto findIter = mScriptSceneObjects.find(sceneObject.getInstanceId());
-		if (findIter != mScriptSceneObjects.end())
-			return findIter->second;
-
-		return nullptr;
-	}
-
-	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(UINT64 instanceId) const
-	{
-		auto findIter = mScriptSceneObjects.find(instanceId);
-		if (findIter != mScriptSceneObjects.end())
-			return findIter->second;
-
-		return nullptr;
-	}
-
-	ScriptGameObjectBase* ScriptGameObjectManager::getScriptGameObject(UINT64 instanceId) const
-	{
-		auto findIter = mScriptSceneObjects.find(instanceId);
-		if (findIter != mScriptSceneObjects.end())
-			return findIter->second;
-
-		auto findIter2 = mScriptComponents.find(instanceId);
-		if (findIter2 != mScriptComponents.end())
-			return findIter2->second;
-
-		return nullptr;
-	}
-
-	void ScriptGameObjectManager::destroyScriptSceneObject(ScriptSceneObject* sceneObject)
-	{
-		UINT64 instanceId = sceneObject->getNativeHandle().getInstanceId();
-		mScriptSceneObjects.erase(instanceId);
-
-		bs_delete(sceneObject);
-	}
-
-	void ScriptGameObjectManager::destroyScriptComponent(ScriptComponent* component)
-	{
-		UINT64 instanceId = component->getNativeHandle().getInstanceId();
-		mScriptComponents.erase(instanceId);
-		mUninitializedScriptComponents.erase(instanceId);
-
-		bs_delete(component);
-	}
-
-	void ScriptGameObjectManager::notifyComponentInitialized(UINT64 instanceId)
-	{
-		mUninitializedScriptComponents.erase(instanceId);
-	}
-
-	void ScriptGameObjectManager::sendComponentResetEvents()
-	{
-		for (auto& scriptObjectEntry : mScriptComponents)
-		{
-			ScriptComponent* scriptComponent = scriptObjectEntry.second;
-			HManagedComponent component = scriptComponent->getNativeHandle();
-
-			if (!component.isDestroyed())
-				component->triggerOnReset();
-		}
-	}
-
-	void ScriptGameObjectManager::sendComponentInitializeEvents()
-	{
-		// Need to make a copy since successful calls will remove entries from mUninitializedScriptComponents
-		UnorderedMap<UINT64, ScriptComponent*> componentsToInitialize = mUninitializedScriptComponents;
-
-		for (auto& scriptObjectEntry : componentsToInitialize)
-		{
-			ScriptComponent* scriptComponent = scriptObjectEntry.second;
-			HManagedComponent component = scriptComponent->getNativeHandle();
-
-			if (!component.isDestroyed())
-				component->triggerOnInitialize();
-		}
-	}
-
-	void ScriptGameObjectManager::onGameObjectDestroyed(const HGameObject& go)
-	{
-		UINT64 instanceId = go.getInstanceId();
-		mUninitializedScriptComponents.erase(instanceId);
-
-		ScriptSceneObject* so = getScriptSceneObject(instanceId);
-		if (so == nullptr)
-			return;
-
-		so->_notifyDestroyed();
-		mScriptSceneObjects.erase(instanceId);
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptGameObjectManager.h"
+#include "BsScriptGameObject.h"
+#include "BsScriptComponent.h"
+#include "BsScriptSceneObject.h"
+#include "BsGameObjectManager.h"
+#include "BsGameObject.h"
+#include "BsComponent.h"
+#include "BsManagedComponent.h"
+#include "BsSceneObject.h"
+#include "BsMonoManager.h"
+#include "BsMonoAssembly.h"
+#include "BsMonoClass.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsScriptObjectManager.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGameObjectManager::ScriptGameObjectEntry::ScriptGameObjectEntry()
+		:instance(nullptr), isComponent(false)
+	{ }
+
+	ScriptGameObjectManager::ScriptGameObjectEntry::ScriptGameObjectEntry(ScriptGameObjectBase* instance, bool isComponent)
+		:instance(instance), isComponent(isComponent)
+	{ }
+
+	ScriptGameObjectManager::ScriptGameObjectManager()
+	{
+		// Calls OnReset on all components after assembly reload happens
+		mOnAssemblyReloadDoneConn = ScriptObjectManager::instance().onRefreshComplete.connect(
+			std::bind(&ScriptGameObjectManager::sendComponentResetEvents, this));
+
+		onGameObjectDestroyedConn = GameObjectManager::instance().onDestroyed.connect(
+			std::bind(&ScriptGameObjectManager::onGameObjectDestroyed, this, _1));
+	}
+
+	ScriptGameObjectManager::~ScriptGameObjectManager()
+	{
+		mOnAssemblyReloadDoneConn.disconnect();
+		onGameObjectDestroyedConn.disconnect();
+	}
+
+	ScriptSceneObject* ScriptGameObjectManager::getOrCreateScriptSceneObject(const HSceneObject& sceneObject)
+	{
+		ScriptSceneObject* so = getScriptSceneObject(sceneObject);
+		if (so != nullptr)
+			return so;
+
+		return createScriptSceneObject(sceneObject);
+	}
+
+	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(const HSceneObject& sceneObject)
+	{
+		MonoClass* sceneObjectClass = ScriptAssemblyManager::instance().getSceneObjectClass();
+		MonoObject* instance = sceneObjectClass->createInstance();
+
+		return createScriptSceneObject(instance, sceneObject);
+	}
+
+	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject)
+	{
+		ScriptSceneObject* so = getScriptSceneObject(sceneObject);
+		if (so != nullptr)
+			BS_EXCEPT(InvalidStateException, "Script object for this SceneObject already exists.");
+
+		ScriptSceneObject* nativeInstance = new (bs_alloc<ScriptSceneObject>()) ScriptSceneObject(existingInstance, sceneObject);
+		mScriptSceneObjects[sceneObject.getInstanceId()] = nativeInstance;
+
+		return nativeInstance;
+	}
+
+	ScriptComponent* ScriptGameObjectManager::createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component)
+	{
+		ScriptGameObjectBase* comp = getScriptComponent(component.getInstanceId());
+		if (comp != nullptr)
+			BS_EXCEPT(InvalidStateException, "Script object for this Component already exists.");
+
+		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(existingInstance);
+		nativeInstance->setNativeHandle(component);
+
+		UINT64 instanceId = component->getInstanceId();
+		mScriptComponents[instanceId] = nativeInstance;
+
+		return nativeInstance;
+	}
+
+	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
+	{
+		auto findIter = mScriptComponents.find(component.getInstanceId());
+		if (findIter != mScriptComponents.end())
+			return findIter->second;
+
+		return nullptr;
+	}
+
+	ScriptComponent* ScriptGameObjectManager::getScriptComponent(UINT64 instanceId) const
+	{
+		auto findIter = mScriptComponents.find(instanceId);
+		if (findIter != mScriptComponents.end())
+			return findIter->second;
+
+		return nullptr;
+	}
+
+	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(const HSceneObject& sceneObject) const
+	{
+		auto findIter = mScriptSceneObjects.find(sceneObject.getInstanceId());
+		if (findIter != mScriptSceneObjects.end())
+			return findIter->second;
+
+		return nullptr;
+	}
+
+	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(UINT64 instanceId) const
+	{
+		auto findIter = mScriptSceneObjects.find(instanceId);
+		if (findIter != mScriptSceneObjects.end())
+			return findIter->second;
+
+		return nullptr;
+	}
+
+	ScriptGameObjectBase* ScriptGameObjectManager::getScriptGameObject(UINT64 instanceId) const
+	{
+		auto findIter = mScriptSceneObjects.find(instanceId);
+		if (findIter != mScriptSceneObjects.end())
+			return findIter->second;
+
+		auto findIter2 = mScriptComponents.find(instanceId);
+		if (findIter2 != mScriptComponents.end())
+			return findIter2->second;
+
+		return nullptr;
+	}
+
+	void ScriptGameObjectManager::destroyScriptSceneObject(ScriptSceneObject* sceneObject)
+	{
+		UINT64 instanceId = sceneObject->getNativeHandle().getInstanceId();
+		mScriptSceneObjects.erase(instanceId);
+
+		bs_delete(sceneObject);
+	}
+
+	void ScriptGameObjectManager::destroyScriptComponent(ScriptComponent* component)
+	{
+		UINT64 instanceId = component->getNativeHandle().getInstanceId();
+		mScriptComponents.erase(instanceId);
+
+		bs_delete(component);
+	}
+
+	void ScriptGameObjectManager::sendComponentResetEvents()
+	{
+		for (auto& scriptObjectEntry : mScriptComponents)
+		{
+			ScriptComponent* scriptComponent = scriptObjectEntry.second;
+			HManagedComponent component = scriptComponent->getNativeHandle();
+
+			if (!component.isDestroyed())
+				component->triggerOnReset();
+		}
+	}
+
+	void ScriptGameObjectManager::wakeRuntimeComponents()
+	{
+		for (auto& scriptObjectEntry : mScriptComponents)
+		{
+			ScriptComponent* scriptComponent = scriptObjectEntry.second;
+			HManagedComponent component = scriptComponent->getNativeHandle();
+
+			if (component.isDestroyed() || component->runInEditor())
+				continue;
+
+			component->triggerOnInitialize();
+
+			if(component->SO()->getActive())
+				component->triggerOnEnable();
+		}
+	}
+
+	void ScriptGameObjectManager::onGameObjectDestroyed(const HGameObject& go)
+	{
+		UINT64 instanceId = go.getInstanceId();
+
+		ScriptSceneObject* so = getScriptSceneObject(instanceId);
+		if (so == nullptr)
+			return;
+
+		so->_notifyDestroyed();
+		mScriptSceneObjects.erase(instanceId);
+	}
 }

+ 106 - 106
Source/SBansheeEngine/Source/BsScriptObjectManager.cpp

@@ -1,107 +1,107 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsScriptObjectManager.h"
-#include "BsScriptObject.h"
-#include "BsMonoManager.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsGameObjectManager.h"
-#include "BsMonoAssembly.h"
-
-namespace BansheeEngine
-{
-	ScriptObjectManager::ScriptObjectManager()
-		:mFinalizedQueueIdx(0)
-	{
-
-	}
-
-	ScriptObjectManager::~ScriptObjectManager()
-	{
-		processFinalizedObjects();
-	}
-
-	void ScriptObjectManager::registerScriptObject(ScriptObjectBase* instance)
-	{
-		mScriptObjects.insert(instance);
-	}
-
-	void ScriptObjectManager::unregisterScriptObject(ScriptObjectBase* instance)
-	{
-		mScriptObjects.erase(instance);
-	}
-
-	void ScriptObjectManager::refreshAssemblies(const Vector<std::pair<String, Path>>& assemblies)
-	{
-		Map<ScriptObjectBase*, ScriptObjectBackup> backupData;
-
-		onRefreshStarted();
-
-		// Make sure any managed game objects are properly destroyed so their OnDestroy callbacks fire before unloading the domain
-		GameObjectManager::instance().destroyQueuedObjects();
-
-		for (auto& scriptObject : mScriptObjects)
-			backupData[scriptObject] = scriptObject->beginRefresh();
-
-		MonoManager::instance().unloadScriptDomain();
-		// Unload script domain should trigger finalizers on everything, but since we usually delay
-		// their processing we need to manually trigger it here.
-		processFinalizedObjects();
-
-		for (auto& scriptObject : mScriptObjects)
-			assert(scriptObject->isPersistent() && "Non-persistent ScriptObject alive after domain unload.");
-
-		for (auto& scriptObject : mScriptObjects)
-			scriptObject->_clearManagedInstance();
-
-		ScriptAssemblyManager::instance().clearAssemblyInfo();
-
-		for (auto& assemblyPair : assemblies)
-		{
-			MonoManager::instance().loadAssembly(assemblyPair.second.toString(), assemblyPair.first);
-			ScriptAssemblyManager::instance().loadAssemblyInfo(assemblyPair.first);
-		}
-
-		Vector<ScriptObjectBase*> scriptObjCopy(mScriptObjects.size()); // Store originals as we could add new objects during the next iteration
-		UINT32 idx = 0;
-		for (auto& scriptObject : mScriptObjects)
-			scriptObjCopy[idx++] = scriptObject;
-
-		onRefreshDomainLoaded();
-
-		for (auto& scriptObject : scriptObjCopy)
-			scriptObject->_restoreManagedInstance();
-
-		for (auto& scriptObject : scriptObjCopy)
-			scriptObject->endRefresh(backupData[scriptObject]);
-
-		onRefreshComplete();
-	}
-
-	void ScriptObjectManager::notifyObjectFinalized(ScriptObjectBase* instance)
-	{
-		assert(instance != nullptr);
-
-		BS_LOCK_MUTEX(mMutex);
-		mFinalizedObjects[mFinalizedQueueIdx].push_back(instance);
-	}
-
-	void ScriptObjectManager::update()
-	{
-		processFinalizedObjects();
-	}
-
-	void ScriptObjectManager::processFinalizedObjects()
-	{
-		UINT32 readQueueIdx = 0;
-		{
-			BS_LOCK_MUTEX(mMutex);
-			readQueueIdx = mFinalizedQueueIdx;
-			mFinalizedQueueIdx = (mFinalizedQueueIdx + 1) % 2;
-		}
-		
-		for (auto& finalizedObj : mFinalizedObjects[readQueueIdx])
-			finalizedObj->_onManagedInstanceDeleted();
-
-		mFinalizedObjects[readQueueIdx].clear();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptObjectManager.h"
+#include "BsScriptObject.h"
+#include "BsMonoManager.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsGameObjectManager.h"
+#include "BsMonoAssembly.h"
+
+namespace BansheeEngine
+{
+	ScriptObjectManager::ScriptObjectManager()
+		:mFinalizedQueueIdx(0)
+	{
+
+	}
+
+	ScriptObjectManager::~ScriptObjectManager()
+	{
+		processFinalizedObjects();
+	}
+
+	void ScriptObjectManager::registerScriptObject(ScriptObjectBase* instance)
+	{
+		mScriptObjects.insert(instance);
+	}
+
+	void ScriptObjectManager::unregisterScriptObject(ScriptObjectBase* instance)
+	{
+		mScriptObjects.erase(instance);
+	}
+
+	void ScriptObjectManager::refreshAssemblies(const Vector<std::pair<String, Path>>& assemblies)
+	{
+		Map<ScriptObjectBase*, ScriptObjectBackup> backupData;
+
+		onRefreshStarted();
+
+		// Make sure any managed game objects are properly destroyed so their OnDestroy callbacks fire before unloading the domain
+		GameObjectManager::instance().destroyQueuedObjects();
+
+		for (auto& scriptObject : mScriptObjects)
+			backupData[scriptObject] = scriptObject->beginRefresh();
+
+		MonoManager::instance().unloadScriptDomain();
+		// Unload script domain should trigger finalizers on everything, but since we usually delay
+		// their processing we need to manually trigger it here.
+		processFinalizedObjects();
+
+		for (auto& scriptObject : mScriptObjects)
+			assert(scriptObject->isPersistent() && "Non-persistent ScriptObject alive after domain unload.");
+
+		for (auto& scriptObject : mScriptObjects)
+			scriptObject->_clearManagedInstance();
+
+		ScriptAssemblyManager::instance().clearAssemblyInfo();
+
+		for (auto& assemblyPair : assemblies)
+		{
+			MonoManager::instance().loadAssembly(assemblyPair.second.toString(), assemblyPair.first);
+			ScriptAssemblyManager::instance().loadAssemblyInfo(assemblyPair.first);
+		}
+
+		Vector<ScriptObjectBase*> scriptObjCopy(mScriptObjects.size()); // Store originals as we could add new objects during the next iteration
+		UINT32 idx = 0;
+		for (auto& scriptObject : mScriptObjects)
+			scriptObjCopy[idx++] = scriptObject;
+
+		onRefreshDomainLoaded();
+
+		for (auto& scriptObject : scriptObjCopy)
+			scriptObject->_restoreManagedInstance();
+
+		for (auto& scriptObject : scriptObjCopy)
+			scriptObject->endRefresh(backupData[scriptObject]);
+
+		onRefreshComplete();
+	}
+
+	void ScriptObjectManager::notifyObjectFinalized(ScriptObjectBase* instance)
+	{
+		assert(instance != nullptr);
+
+		BS_LOCK_MUTEX(mMutex);
+		mFinalizedObjects[mFinalizedQueueIdx].push_back(instance);
+	}
+
+	void ScriptObjectManager::update()
+	{
+		processFinalizedObjects();
+	}
+
+	void ScriptObjectManager::processFinalizedObjects()
+	{
+		UINT32 readQueueIdx = 0;
+		{
+			BS_LOCK_MUTEX(mMutex);
+			readQueueIdx = mFinalizedQueueIdx;
+			mFinalizedQueueIdx = (mFinalizedQueueIdx + 1) % 2;
+		}
+		
+		for (auto& finalizedObj : mFinalizedObjects[readQueueIdx])
+			finalizedObj->_onManagedInstanceDeleted();
+
+		mFinalizedObjects[readQueueIdx].clear();
+	}
 }