Răsfoiți Sursa

Fixing various issue with assigning colliders to rigidbodies
Fixed a crash when unregistering a rigidbody
Fixed rigidbody mass distribution update when no colliders are present
Fixed labels on rigidbody's inspector

BearishSun 9 ani în urmă
părinte
comite
2c4a2b30d4

+ 123 - 123
Documentation/GitHub/features.md

@@ -1,124 +1,124 @@
-# Features
-
-Here you will find a complete list of all currently available features. Banshee is current in development and more features are being added frequently.
-
-## Editor
-* __Asset management__
-  * Simple drag and drop import for many popular formats
-  * Automatic reimport of externally modified assets (e.g. modify a shader, see changes in editor right away)
-  * Asset modifications immediately reflected in-game (resource hot-swap)
-  * Version control friendly format
-* __Powerful object inspector__
-  * Exposes script object properties for artists/designers
-  * Automatically generated GUI for custom classes
-  * Customize visible elements via attributes or create GUI manually
-* __Level creation__
-  * Simple drag and drop interface
-  * Traditional set of tools (Move/Scale/Rotate/Select, etc.)
-  * Interface for creating custom 2D and 3D tools
-* __Prefab system__
-  * Save parts or entire levels as prefabs so they may be re-used later
-  * Separate larger levels into smaller prefabs for easier loading
-  * Reduce conflicts when multiple people are working on the same level
-  * Customize individual prefab instances without breaking the prefab link
-  * Supports nesting and complex hierarchies to ensure maintaining complex levels is easy
-* __Play in editor__
-  * Compile all scripts within editor
-  * Scripts and data transparently reloaded after compilation so changes may be tested immediately
-  * Pause and frame-step to better test and debug your game
-  * Analyze and modify scene while playing
-* __Fully extensible__
-  * Specialized scripting API only for editor extensions
-  * Easy to use without needing to know about engine internals
-  * Extend almost anything. Create:
-	* Custom editor windows
-	* Custom object inspectors
-	* Custom 2D/3D tools
-	* Code for automating common tasks
-* __Game publishing__
-  * Build a game ready for distribution from within editor
-  * One click build process, just choose a platform and go
-  * Automatically detects required resources
-  * Automatically packages and outputs an executable
-* __Customizable frontend__
-  * Dockable layout and floating windows
-  * Custom GUI skin & localization support
-   
-## Core
-* __Quality design__
-  * Modern code using C++14
-  * Clean layered design
-  * Fully documented
-  * Modular & plugin based
-  * Minimal third-party dependencies
-  * Multiplatform ready
-* __Renderer__
-  * DX9, DX11 and OpenGL 4.3 render systems
-  * Multi-threaded rendering
-  * Powerful material system
-    * BansheeFX language for material definitions
-    * Shader parsing for HLSL9, HLSL11 and GLSL
-* __Asset pipeline__
-  * Asynchronous resource loading
-  * Extensible importer system
-  * Available importer plugins for:
-    * FBX, OBJ, DAE meshes
-    * PNG, PSD, BMP, JPG, ... images
-    * OTF, TTF fonts
-    * HLSL9, HLSL11, GLSL shaders
-* __GUI system__
-  * Unicode text rendering and input
-  * Easy to use layout based system
-  * Many common GUI controls
-  * Fully skinnable
-  * Automatic batching for fast rendering
-  * Supports texture atlases
-  * Supports arbitrary 3D transformations
-  * Localization support (string tables)
-* __Input__
-  * Mouse/Keyboard/Gamepad support
-  * Provides both raw and OS input
-  * Virtual input with built-in key mapping
-  * Virtual axes for analog input devices
-* __Physics__
-  * Implemented using NVIDIA PhysX
-  * Multi-threaded for best performance
-  * Abstract plugin interface extensible for other physics implementations (e.g. Havok, Bullet)
-  * Supported features
-    * Colliders (Box, Sphere, Capsule, Mesh)
-    * Triggers
-    * Rigidbody
-    * Character controller
-    * Joints (Fixed, Distance, Hinge, Spherical, Slider, D6)
-	* Scene queries
-	* Collision filtering
-	* Discrete or continous collision detection
-* __Scripting__
-  * C# 5.0
-  * Separate high level engine API
-  * Integrated runtime for maximum performance
-  * Full access to .NET framework
-  * Integration with Visual Studio
-  * Automatic serialization
-	* Works with custom components, resources or arbitrary types
-	* Save/load data with no additional code
-	* Handles complex types (e.g. array, list, dictionary) and references
-	* Fast and small memory footprint
-* __Other__
-  * CPU & GPU profiler
-  * Advanced run-time type information for C++ code
-    * Iterate over class fields, safely cast objects, clone objects, detect base types
-	* Find references to specific objects (e.g. all resources used in a scene)
-	* Serialize/deserialize with no additional code and with automatic versioning
-	* Generate diffs
-  * Utility library
-    * Math
-	* File system
-    * Events
-	* Thread pool
-    * Task scheduler
-    * Logging
-	* Debug drawing
-	* Crash reporting
-	* Unit testing
+# Features
+
+Here you will find a complete list of all currently available features. Banshee is current in development and more features are being added frequently.
+
+## Editor
+* __Asset management__
+  * Simple drag and drop import for many popular formats
+  * Automatic reimport of externally modified assets (e.g. modify a shader, see changes in editor right away)
+  * Asset modifications immediately reflected in-game (resource hot-swap)
+  * Version control friendly format
+* __Powerful object inspector__
+  * Exposes script object properties for artists/designers
+  * Automatically generated GUI for custom classes
+  * Customize visible elements via attributes or create GUI manually
+* __Level creation__
+  * Simple drag and drop interface
+  * Traditional set of tools (Move/Scale/Rotate/Select, etc.)
+  * Interface for creating custom 2D and 3D tools
+* __Prefab system__
+  * Save parts or entire levels as prefabs so they may be re-used later
+  * Separate larger levels into smaller prefabs for easier loading
+  * Reduce conflicts when multiple people are working on the same level
+  * Customize individual prefab instances without breaking the prefab link
+  * Supports nesting and complex hierarchies to ensure maintaining complex levels is easy
+* __Play in editor__
+  * Compile all scripts within editor
+  * Scripts and data transparently reloaded after compilation so changes may be tested immediately
+  * Pause and frame-step to better test and debug your game
+  * Analyze and modify scene while playing
+* __Fully extensible__
+  * Specialized scripting API only for editor extensions
+  * Easy to use without needing to know about engine internals
+  * Extend almost anything. Create:
+	* Custom editor windows
+	* Custom object inspectors
+	* Custom 2D/3D tools
+	* Code for automating common tasks
+* __Game publishing__
+  * Build a game ready for distribution from within editor
+  * One click build process, just choose a platform and go
+  * Automatically detects required resources
+  * Automatically packages and outputs an executable
+* __Customizable frontend__
+  * Dockable layout and floating windows
+  * Custom GUI skin & localization support
+   
+## Core
+* __Quality design__
+  * Modern code using C++14
+  * Clean layered design
+  * Fully documented
+  * Modular & plugin based
+  * Minimal third-party dependencies
+  * Multiplatform ready
+* __Renderer__
+  * DX9, DX11 and OpenGL 4.3 render systems
+  * Multi-threaded rendering
+  * Powerful material system
+    * BansheeFX language for material definitions
+    * Shader parsing for HLSL9, HLSL11 and GLSL
+* __Asset pipeline__
+  * Asynchronous resource loading
+  * Extensible importer system
+  * Available importer plugins for:
+    * FBX, OBJ, DAE meshes
+    * PNG, PSD, BMP, JPG, ... images
+    * OTF, TTF fonts
+    * HLSL9, HLSL11, GLSL shaders
+* __GUI system__
+  * Unicode text rendering and input
+  * Easy to use layout based system
+  * Many common GUI controls
+  * Fully skinnable
+  * Automatic batching for fast rendering
+  * Supports texture atlases
+  * Supports arbitrary 3D transformations
+  * Localization support (string tables)
+* __Input__
+  * Mouse/Keyboard/Gamepad support
+  * Provides both raw and OS input
+  * Virtual input with built-in key mapping
+  * Virtual axes for analog input devices
+* __Physics__
+  * Implemented using NVIDIA PhysX
+  * Multi-threaded for best performance
+  * Abstract plugin interface extensible for other physics implementations (e.g. Havok, Bullet)
+  * Supported features
+    * Colliders (Box, Sphere, Capsule, Mesh)
+    * Triggers
+    * Rigidbody
+    * Character controller
+    * Joints (Fixed, Distance, Hinge, Spherical, Slider, D6)
+	* Scene queries
+	* Collision filtering
+	* Discrete or continuous collision detection
+* __Scripting__
+  * C# 5.0
+  * Separate high level engine API
+  * Integrated runtime for maximum performance
+  * Full access to .NET framework
+  * Integration with Visual Studio
+  * Automatic serialization
+	* Works with custom components, resources or arbitrary types
+	* Save/load data with no additional code
+	* Handles complex types (e.g. array, list, dictionary) and references
+	* Fast and small memory footprint
+* __Other__
+  * CPU & GPU profiler
+  * Advanced run-time type information for C++ code
+    * Iterate over class fields, safely cast objects, clone objects, detect base types
+	* Find references to specific objects (e.g. all resources used in a scene)
+	* Serialize/deserialize with no additional code and with automatic versioning
+	* Generate diffs
+  * Utility library
+    * Math
+	* File system
+    * Events
+	* Thread pool
+    * Task scheduler
+    * Logging
+	* Debug drawing
+	* Crash reporting
+	* Unit testing
 	* Custom memory allocators

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

@@ -132,9 +132,9 @@ namespace BansheeEngine
 		/**
 		 * 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.
+		 * @param[in] rigidbody		New rigidbody to assign as the parent to the collider.
+		 * @param[in] 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);
 

+ 496 - 495
Source/BansheeCore/Source/BsCRigidbody.cpp

@@ -1,496 +1,497 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsCRigidbody.h"
-#include "BsSceneObject.h"
-#include "BsCCollider.h"
-#include "BsCJoint.h"
-#include "BsCRigidbodyRTTI.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	CRigidbody::CRigidbody(const HSceneObject& parent)
-		: Component(parent)
-	{
-		setName("Rigidbody");
-
-		mNotifyFlags = (TransformChangedFlags)(TCF_Parent | TCF_Transform);
-	}
-
-	void CRigidbody::move(const Vector3& position)
-	{
-		if (mInternal != nullptr)
-			mInternal->move(position);
-	}
-
-	void CRigidbody::rotate(const Quaternion& rotation)
-	{
-		if (mInternal != nullptr)
-			mInternal->rotate(rotation);
-	}
-
-	void CRigidbody::setMass(float mass)
-	{
-		mMass = mass;
-
-		if(mInternal != nullptr)
-			mInternal->setMass(mass);
-	}
-
-	void CRigidbody::setIsKinematic(bool kinematic)
-	{
-		if (mIsKinematic == kinematic)
-			return;
-
-		mIsKinematic = kinematic;
-		
-		if (mInternal != nullptr)
-		{
-			mInternal->setIsKinematic(kinematic);
-
-			clearColliders();
-			updateColliders();
-		}
-	}
-
-	bool CRigidbody::isSleeping() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->isSleeping();
-
-		return true;
-	}
-
-	void CRigidbody::sleep()
-	{
-		if (mInternal != nullptr)
-			return mInternal->sleep();
-	}
-
-	void CRigidbody::wakeUp()
-	{
-		if (mInternal != nullptr)
-			return mInternal->wakeUp();
-	}
-
-	void CRigidbody::setSleepThreshold(float threshold)
-	{
-		mSleepThreshold = threshold;
-
-		if (mInternal != nullptr)
-			mInternal->setSleepThreshold(threshold);
-	}
-
-	void CRigidbody::setUseGravity(bool gravity)
-	{
-		mUseGravity = gravity;
-
-		if (mInternal != nullptr)
-			mInternal->setUseGravity(gravity);
-	}
-
-	void CRigidbody::setVelocity(const Vector3& velocity)
-	{
-		if (mInternal != nullptr)
-			mInternal->setVelocity(velocity);
-	}
-
-	Vector3 CRigidbody::getVelocity() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getVelocity();
-
-		return Vector3::ZERO;
-	}
-
-	void CRigidbody::setAngularVelocity(const Vector3& velocity)
-	{
-		if (mInternal != nullptr)
-			mInternal->setAngularVelocity(velocity);
-	}
-
-	inline Vector3 CRigidbody::getAngularVelocity() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getAngularVelocity();
-
-		return Vector3::ZERO;
-	}
-
-	void CRigidbody::setDrag(float drag)
-	{
-		mLinearDrag = drag;
-
-		if (mInternal != nullptr)
-			mInternal->setDrag(drag);
-	}
-
-	void CRigidbody::setAngularDrag(float drag)
-	{
-		mAngularDrag = drag;
-
-		if (mInternal != nullptr)
-			mInternal->setAngularDrag(drag);
-	}
-
-	void CRigidbody::setInertiaTensor(const Vector3& tensor)
-	{
-		mInertiaTensor = tensor;
-
-		if (mInternal != nullptr)
-			mInternal->setInertiaTensor(tensor);
-	}
-
-	Vector3 CRigidbody::getInertiaTensor() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getInertiaTensor();
-
-		return Vector3::ZERO;
-	}
-
-	void CRigidbody::setMaxAngularVelocity(float maxVelocity)
-	{
-		mMaxAngularVelocity = maxVelocity;
-
-		if (mInternal != nullptr)
-			mInternal->setMaxAngularVelocity(maxVelocity);
-	}
-
-	void CRigidbody::setCenterOfMass(const Vector3& position, const Quaternion& rotation)
-	{
-		mCMassPosition = position;
-		mCMassRotation = rotation;
-
-		if (mInternal != nullptr)
-			mInternal->setCenterOfMass(position, rotation);
-	}
-
-	Vector3 CRigidbody::getCenterOfMassPosition() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getCenterOfMassPosition();
-
-		return Vector3::ZERO;
-	}
-
-	Quaternion CRigidbody::getCenterOfMassRotation() const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getCenterOfMassRotation();
-
-		return Quaternion::IDENTITY;
-	}
-
-	void CRigidbody::setPositionSolverCount(UINT32 count)
-	{
-		mPositionSolverCount = count;
-
-		if (mInternal != nullptr)
-			mInternal->setPositionSolverCount(count);
-	}
-
-	void CRigidbody::setVelocitySolverCount(UINT32 count)
-	{
-		mVelocitySolverCount = count;
-
-		if (mInternal != nullptr)
-			mInternal->setVelocitySolverCount(count);
-	}
-
-	void CRigidbody::setInterpolationMode(Rigidbody::InterpolationMode value)
-	{
-		mInterpolationMode = value;
-
-		if (mInternal != nullptr)
-			mInternal->setInterpolationMode(value);
-	}
-
-	void CRigidbody::setCollisionReportMode(CollisionReportMode mode)
-	{
-		if (mCollisionReportMode == mode)
-			return;
-
-		mCollisionReportMode = mode;
-
-		for (auto& entry : mChildren)
-			entry->updateCollisionReportMode();
-	}
-
-	void CRigidbody::setFlags(Rigidbody::Flag flags)
-	{
-		mFlags = flags;
-
-		if (mInternal != nullptr)
-		{
-			mInternal->setFlags(flags);
-			mInternal->updateMassDistribution();
-		}
-	}
-
-	void CRigidbody::addForce(const Vector3& force, ForceMode mode)
-	{
-		if (mInternal != nullptr)
-			mInternal->addForce(force, mode);
-	}
-
-	void CRigidbody::addTorque(const Vector3& torque, ForceMode mode)
-	{
-		if (mInternal != nullptr)
-			mInternal->addTorque(torque, mode);
-	}
-
-	void CRigidbody::addForceAtPoint(const Vector3& force, const Vector3& position, PointForceMode mode)
-	{
-		if (mInternal != nullptr)
-			mInternal->addForceAtPoint(force, position, mode);
-	}
-
-	Vector3 CRigidbody::getVelocityAtPoint(const Vector3& point) const
-	{
-		if (mInternal != nullptr)
-			return mInternal->getVelocityAtPoint(point);
-
-		return Vector3::ZERO;
-	}
-
-	void CRigidbody::_updateMassDistribution()
-	{
-		if (mInternal != nullptr)
-			return mInternal->updateMassDistribution();
-	}
-
-	void CRigidbody::updateColliders()
-	{
-		Stack<HSceneObject> todo;
-		todo.push(SO());
-
-		while(!todo.empty())
-		{
-			HSceneObject currentSO = todo.top();
-			todo.pop();
-
-			if(currentSO->hasComponent<CCollider>())
-			{
-				Vector<HCollider> colliders = currentSO->getComponents<CCollider>();
-				
-				for (auto& entry : colliders)
-				{
-					if (!entry->isValidParent(mThisHandle))
-						continue;
-
-					entry->setRigidbody(mThisHandle, true);
-
-					mChildren.push_back(entry);
-					mInternal->addCollider(entry->_getInternal()->_getInternal());
-				}
-			}
-
-			UINT32 childCount = currentSO->getNumChildren();
-			for (UINT32 i = 0; i < childCount; i++)
-			{
-				HSceneObject child = currentSO->getChild(i);
-
-				if (child->hasComponent<CRigidbody>())
-					continue;
-
-				todo.push(child);
-			}
-		}
-	}
-
-	void CRigidbody::clearColliders()
-	{
-		for (auto& collider : mChildren)
-			collider->setRigidbody(HRigidbody(), true);
-
-		mChildren.clear();
-
-		if (mInternal != nullptr)
-			mInternal->removeColliders();
-	}
-
-	void CRigidbody::addCollider(const HCollider& collider)
-	{
-		if (mInternal == nullptr)
-			return;
-
-		mChildren.push_back(collider);
-		mInternal->addCollider(collider->_getInternal()->_getInternal());
-	}
-
-	void CRigidbody::removeCollider(const HCollider& collider)
-	{
-		if (mInternal == nullptr)
-			return;
-
-		auto iterFind = std::find(mChildren.begin(), mChildren.end(), collider);
-
-		if(iterFind != mChildren.end())
-		{
-			mInternal->removeCollider(collider->_getInternal()->_getInternal());
-			mChildren.erase(iterFind);
-		}
-	}
-
-	void CRigidbody::checkForNestedRigibody()
-	{
-		HSceneObject currentSO = SO()->getParent();
-
-		while(currentSO != nullptr)
-		{
-			if(currentSO->hasComponent<CRigidbody>())
-			{
-				LOGWRN("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->getParent();
-		}
-	}
-
-	void CRigidbody::processCollisionData(CollisionData& data)
-	{
-		if (data.collidersRaw[0] != nullptr)
-		{
-			CCollider* other = (CCollider*)data.collidersRaw[0]->_getOwner(PhysicsOwnerType::Component);
-			data.collider[0] = other->getHandle();
-		}
-
-		if (data.collidersRaw[1] != nullptr)
-		{
-			CCollider* other = (CCollider*)data.collidersRaw[1]->_getOwner(PhysicsOwnerType::Component);
-			data.collider[1] = other->getHandle();
-		}
-	}
-
-	void CRigidbody::destroyInternal()
-	{
-		clearColliders();
-
-		mInternal->_setOwner(PhysicsOwnerType::None, nullptr);
-		mInternal = nullptr;
-	}
-
-	void CRigidbody::triggerOnCollisionBegin(const CollisionData& data)
-	{
-		// Const-cast and modify is okay because we're the only object receiving this event
-		CollisionData& hit = const_cast<CollisionData&>(data);
-		processCollisionData(hit);
-
-		onCollisionBegin(hit);
-	}
-
-	void CRigidbody::triggerOnCollisionStay(const CollisionData& data)
-	{
-		// Const-cast and modify is okay because we're the only object receiving this event
-		CollisionData& hit = const_cast<CollisionData&>(data);
-		processCollisionData(hit);
-
-		onCollisionStay(hit);
-	}
-
-	void CRigidbody::triggerOnCollisionEnd(const CollisionData& data)
-	{
-		// Const-cast and modify is okay because we're the only object receiving this event
-		CollisionData& hit = const_cast<CollisionData&>(data);
-		processCollisionData(hit);
-
-		onCollisionEnd(hit);
-	}
-
-	void CRigidbody::onInitialized()
-	{
-
-	}
-
-	void CRigidbody::onDestroyed()
-	{
-		destroyInternal();
-	}
-
-	void CRigidbody::onDisabled()
-	{
-		destroyInternal();
-	}
-
-	void CRigidbody::onEnabled()
-	{
-		mInternal = Rigidbody::create(SO());
-		mInternal->_setOwner(PhysicsOwnerType::Component, this);
-
-		updateColliders();
-
-#if BS_DEBUG_MODE
-		checkForNestedRigibody();
-#endif
-
-		mInternal->onCollisionBegin.connect(std::bind(&CRigidbody::triggerOnCollisionBegin, this, _1));
-		mInternal->onCollisionStay.connect(std::bind(&CRigidbody::triggerOnCollisionStay, this, _1));
-		mInternal->onCollisionEnd.connect(std::bind(&CRigidbody::triggerOnCollisionEnd, this, _1));
-
-		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
-
-		// Note: Merge into one call to avoid many virtual function calls
-		mInternal->setPositionSolverCount(mPositionSolverCount);
-		mInternal->setVelocitySolverCount(mVelocitySolverCount);
-		mInternal->setMaxAngularVelocity(mMaxAngularVelocity);
-		mInternal->setDrag(mLinearDrag);
-		mInternal->setAngularDrag(mAngularDrag);
-		mInternal->setSleepThreshold(mSleepThreshold);
-		mInternal->setUseGravity(mUseGravity);
-		mInternal->setIsKinematic(mIsKinematic);
-		mInternal->setInterpolationMode(mInterpolationMode);
-		mInternal->setFlags(mFlags);
-
-		if(((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) == 0)
-		{
-			mInternal->setCenterOfMass(mCMassPosition, mCMassRotation);
-			mInternal->setInertiaTensor(mInertiaTensor);
-			mInternal->setMass(mMass);
-		}
-		else
-		{
-			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoMass) == 0)
-				mInternal->setMass(mMass);
-
-			mInternal->updateMassDistribution();
-		}
-	}
-
-	void CRigidbody::onTransformChanged(TransformChangedFlags flags)
-	{
-		if (!SO()->getActive())
-			return;
-
-		if((flags & TCF_Parent) != 0)
-		{
-			clearColliders();
-			updateColliders();
-
-			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) != 0)
-				mInternal->updateMassDistribution();
-
-#if BS_DEBUG_MODE
-			checkForNestedRigibody();
-#endif
-		}
-
-		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
-
-		if (mParentJoint != nullptr)
-			mParentJoint->notifyRigidbodyMoved(mThisHandle);
-	}
-
-	RTTITypeBase* CRigidbody::getRTTIStatic()
-	{
-		return CRigidbodyRTTI::instance();
-	}
-
-	RTTITypeBase* CRigidbody::getRTTI() const
-	{
-		return CRigidbody::getRTTIStatic();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsCRigidbody.h"
+#include "BsSceneObject.h"
+#include "BsCCollider.h"
+#include "BsCJoint.h"
+#include "BsCRigidbodyRTTI.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	CRigidbody::CRigidbody(const HSceneObject& parent)
+		: Component(parent)
+	{
+		setName("Rigidbody");
+
+		mNotifyFlags = (TransformChangedFlags)(TCF_Parent | TCF_Transform);
+	}
+
+	void CRigidbody::move(const Vector3& position)
+	{
+		if (mInternal != nullptr)
+			mInternal->move(position);
+	}
+
+	void CRigidbody::rotate(const Quaternion& rotation)
+	{
+		if (mInternal != nullptr)
+			mInternal->rotate(rotation);
+	}
+
+	void CRigidbody::setMass(float mass)
+	{
+		mMass = mass;
+
+		if(mInternal != nullptr)
+			mInternal->setMass(mass);
+	}
+
+	void CRigidbody::setIsKinematic(bool kinematic)
+	{
+		if (mIsKinematic == kinematic)
+			return;
+
+		mIsKinematic = kinematic;
+		
+		if (mInternal != nullptr)
+		{
+			mInternal->setIsKinematic(kinematic);
+
+			clearColliders();
+			updateColliders();
+		}
+	}
+
+	bool CRigidbody::isSleeping() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->isSleeping();
+
+		return true;
+	}
+
+	void CRigidbody::sleep()
+	{
+		if (mInternal != nullptr)
+			return mInternal->sleep();
+	}
+
+	void CRigidbody::wakeUp()
+	{
+		if (mInternal != nullptr)
+			return mInternal->wakeUp();
+	}
+
+	void CRigidbody::setSleepThreshold(float threshold)
+	{
+		mSleepThreshold = threshold;
+
+		if (mInternal != nullptr)
+			mInternal->setSleepThreshold(threshold);
+	}
+
+	void CRigidbody::setUseGravity(bool gravity)
+	{
+		mUseGravity = gravity;
+
+		if (mInternal != nullptr)
+			mInternal->setUseGravity(gravity);
+	}
+
+	void CRigidbody::setVelocity(const Vector3& velocity)
+	{
+		if (mInternal != nullptr)
+			mInternal->setVelocity(velocity);
+	}
+
+	Vector3 CRigidbody::getVelocity() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getVelocity();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setAngularVelocity(const Vector3& velocity)
+	{
+		if (mInternal != nullptr)
+			mInternal->setAngularVelocity(velocity);
+	}
+
+	inline Vector3 CRigidbody::getAngularVelocity() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getAngularVelocity();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setDrag(float drag)
+	{
+		mLinearDrag = drag;
+
+		if (mInternal != nullptr)
+			mInternal->setDrag(drag);
+	}
+
+	void CRigidbody::setAngularDrag(float drag)
+	{
+		mAngularDrag = drag;
+
+		if (mInternal != nullptr)
+			mInternal->setAngularDrag(drag);
+	}
+
+	void CRigidbody::setInertiaTensor(const Vector3& tensor)
+	{
+		mInertiaTensor = tensor;
+
+		if (mInternal != nullptr)
+			mInternal->setInertiaTensor(tensor);
+	}
+
+	Vector3 CRigidbody::getInertiaTensor() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getInertiaTensor();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setMaxAngularVelocity(float maxVelocity)
+	{
+		mMaxAngularVelocity = maxVelocity;
+
+		if (mInternal != nullptr)
+			mInternal->setMaxAngularVelocity(maxVelocity);
+	}
+
+	void CRigidbody::setCenterOfMass(const Vector3& position, const Quaternion& rotation)
+	{
+		mCMassPosition = position;
+		mCMassRotation = rotation;
+
+		if (mInternal != nullptr)
+			mInternal->setCenterOfMass(position, rotation);
+	}
+
+	Vector3 CRigidbody::getCenterOfMassPosition() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getCenterOfMassPosition();
+
+		return Vector3::ZERO;
+	}
+
+	Quaternion CRigidbody::getCenterOfMassRotation() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getCenterOfMassRotation();
+
+		return Quaternion::IDENTITY;
+	}
+
+	void CRigidbody::setPositionSolverCount(UINT32 count)
+	{
+		mPositionSolverCount = count;
+
+		if (mInternal != nullptr)
+			mInternal->setPositionSolverCount(count);
+	}
+
+	void CRigidbody::setVelocitySolverCount(UINT32 count)
+	{
+		mVelocitySolverCount = count;
+
+		if (mInternal != nullptr)
+			mInternal->setVelocitySolverCount(count);
+	}
+
+	void CRigidbody::setInterpolationMode(Rigidbody::InterpolationMode value)
+	{
+		mInterpolationMode = value;
+
+		if (mInternal != nullptr)
+			mInternal->setInterpolationMode(value);
+	}
+
+	void CRigidbody::setCollisionReportMode(CollisionReportMode mode)
+	{
+		if (mCollisionReportMode == mode)
+			return;
+
+		mCollisionReportMode = mode;
+
+		for (auto& entry : mChildren)
+			entry->updateCollisionReportMode();
+	}
+
+	void CRigidbody::setFlags(Rigidbody::Flag flags)
+	{
+		mFlags = flags;
+
+		if (mInternal != nullptr)
+		{
+			mInternal->setFlags(flags);
+			mInternal->updateMassDistribution();
+		}
+	}
+
+	void CRigidbody::addForce(const Vector3& force, ForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addForce(force, mode);
+	}
+
+	void CRigidbody::addTorque(const Vector3& torque, ForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addTorque(torque, mode);
+	}
+
+	void CRigidbody::addForceAtPoint(const Vector3& force, const Vector3& position, PointForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addForceAtPoint(force, position, mode);
+	}
+
+	Vector3 CRigidbody::getVelocityAtPoint(const Vector3& point) const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getVelocityAtPoint(point);
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::_updateMassDistribution()
+	{
+		if (mInternal != nullptr)
+			return mInternal->updateMassDistribution();
+	}
+
+	void CRigidbody::updateColliders()
+	{
+		Stack<HSceneObject> todo;
+		todo.push(SO());
+
+		while(!todo.empty())
+		{
+			HSceneObject currentSO = todo.top();
+			todo.pop();
+
+			if(currentSO->hasComponent<CCollider>())
+			{
+				Vector<HCollider> colliders = currentSO->getComponents<CCollider>();
+				
+				for (auto& entry : colliders)
+				{
+					if (!entry->isValidParent(mThisHandle))
+						continue;
+
+					entry->setRigidbody(mThisHandle, true);
+					entry->_getInternal()->setRigidbody(mInternal.get());
+
+					mChildren.push_back(entry);
+					mInternal->addCollider(entry->_getInternal()->_getInternal());
+				}
+			}
+
+			UINT32 childCount = currentSO->getNumChildren();
+			for (UINT32 i = 0; i < childCount; i++)
+			{
+				HSceneObject child = currentSO->getChild(i);
+
+				if (child->hasComponent<CRigidbody>())
+					continue;
+
+				todo.push(child);
+			}
+		}
+	}
+
+	void CRigidbody::clearColliders()
+	{
+		for (auto& collider : mChildren)
+			collider->setRigidbody(HRigidbody(), true);
+
+		mChildren.clear();
+
+		if (mInternal != nullptr)
+			mInternal->removeColliders();
+	}
+
+	void CRigidbody::addCollider(const HCollider& collider)
+	{
+		if (mInternal == nullptr)
+			return;
+
+		mChildren.push_back(collider);
+		mInternal->addCollider(collider->_getInternal()->_getInternal());
+	}
+
+	void CRigidbody::removeCollider(const HCollider& collider)
+	{
+		if (mInternal == nullptr)
+			return;
+
+		auto iterFind = std::find(mChildren.begin(), mChildren.end(), collider);
+
+		if(iterFind != mChildren.end())
+		{
+			mInternal->removeCollider(collider->_getInternal()->_getInternal());
+			mChildren.erase(iterFind);
+		}
+	}
+
+	void CRigidbody::checkForNestedRigibody()
+	{
+		HSceneObject currentSO = SO()->getParent();
+
+		while(currentSO != nullptr)
+		{
+			if(currentSO->hasComponent<CRigidbody>())
+			{
+				LOGWRN("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->getParent();
+		}
+	}
+
+	void CRigidbody::processCollisionData(CollisionData& data)
+	{
+		if (data.collidersRaw[0] != nullptr)
+		{
+			CCollider* other = (CCollider*)data.collidersRaw[0]->_getOwner(PhysicsOwnerType::Component);
+			data.collider[0] = other->getHandle();
+		}
+
+		if (data.collidersRaw[1] != nullptr)
+		{
+			CCollider* other = (CCollider*)data.collidersRaw[1]->_getOwner(PhysicsOwnerType::Component);
+			data.collider[1] = other->getHandle();
+		}
+	}
+
+	void CRigidbody::destroyInternal()
+	{
+		clearColliders();
+
+		mInternal->_setOwner(PhysicsOwnerType::None, nullptr);
+		mInternal = nullptr;
+	}
+
+	void CRigidbody::triggerOnCollisionBegin(const CollisionData& data)
+	{
+		// Const-cast and modify is okay because we're the only object receiving this event
+		CollisionData& hit = const_cast<CollisionData&>(data);
+		processCollisionData(hit);
+
+		onCollisionBegin(hit);
+	}
+
+	void CRigidbody::triggerOnCollisionStay(const CollisionData& data)
+	{
+		// Const-cast and modify is okay because we're the only object receiving this event
+		CollisionData& hit = const_cast<CollisionData&>(data);
+		processCollisionData(hit);
+
+		onCollisionStay(hit);
+	}
+
+	void CRigidbody::triggerOnCollisionEnd(const CollisionData& data)
+	{
+		// Const-cast and modify is okay because we're the only object receiving this event
+		CollisionData& hit = const_cast<CollisionData&>(data);
+		processCollisionData(hit);
+
+		onCollisionEnd(hit);
+	}
+
+	void CRigidbody::onInitialized()
+	{
+
+	}
+
+	void CRigidbody::onDestroyed()
+	{
+		destroyInternal();
+	}
+
+	void CRigidbody::onDisabled()
+	{
+		destroyInternal();
+	}
+
+	void CRigidbody::onEnabled()
+	{
+		mInternal = Rigidbody::create(SO());
+		mInternal->_setOwner(PhysicsOwnerType::Component, this);
+
+		updateColliders();
+
+#if BS_DEBUG_MODE
+		checkForNestedRigibody();
+#endif
+
+		mInternal->onCollisionBegin.connect(std::bind(&CRigidbody::triggerOnCollisionBegin, this, _1));
+		mInternal->onCollisionStay.connect(std::bind(&CRigidbody::triggerOnCollisionStay, this, _1));
+		mInternal->onCollisionEnd.connect(std::bind(&CRigidbody::triggerOnCollisionEnd, this, _1));
+
+		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+
+		// Note: Merge into one call to avoid many virtual function calls
+		mInternal->setPositionSolverCount(mPositionSolverCount);
+		mInternal->setVelocitySolverCount(mVelocitySolverCount);
+		mInternal->setMaxAngularVelocity(mMaxAngularVelocity);
+		mInternal->setDrag(mLinearDrag);
+		mInternal->setAngularDrag(mAngularDrag);
+		mInternal->setSleepThreshold(mSleepThreshold);
+		mInternal->setUseGravity(mUseGravity);
+		mInternal->setIsKinematic(mIsKinematic);
+		mInternal->setInterpolationMode(mInterpolationMode);
+		mInternal->setFlags(mFlags);
+
+		if(((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) == 0)
+		{
+			mInternal->setCenterOfMass(mCMassPosition, mCMassRotation);
+			mInternal->setInertiaTensor(mInertiaTensor);
+			mInternal->setMass(mMass);
+		}
+		else
+		{
+			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoMass) == 0)
+				mInternal->setMass(mMass);
+
+			mInternal->updateMassDistribution();
+		}
+	}
+
+	void CRigidbody::onTransformChanged(TransformChangedFlags flags)
+	{
+		if (!SO()->getActive())
+			return;
+
+		if((flags & TCF_Parent) != 0)
+		{
+			clearColliders();
+			updateColliders();
+
+			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) != 0)
+				mInternal->updateMassDistribution();
+
+#if BS_DEBUG_MODE
+			checkForNestedRigibody();
+#endif
+		}
+
+		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+
+		if (mParentJoint != nullptr)
+			mParentJoint->notifyRigidbodyMoved(mThisHandle);
+	}
+
+	RTTITypeBase* CRigidbody::getRTTIStatic()
+	{
+		return CRigidbodyRTTI::instance();
+	}
+
+	RTTITypeBase* CRigidbody::getRTTI() const
+	{
+		return CRigidbody::getRTTIStatic();
+	}
 }

+ 136 - 135
Source/BansheeCore/Source/BsPhysics.cpp

@@ -1,136 +1,137 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysics.h"
-#include "BsRigidbody.h"
-#include "BsRay.h"
-#include "BsCCollider.h"
-
-namespace BansheeEngine
-{
-	Physics::Physics(const PHYSICS_INIT_DESC& init)
-	{
-		memset(mCollisionMap, 1, CollisionMapSize * CollisionMapSize * sizeof(bool));
-	}
-
-	void Physics::toggleCollision(UINT64 groupA, UINT64 groupB, bool enabled)
-	{
-		assert(groupA < CollisionMapSize && groupB < CollisionMapSize);
-
-		mMutex.lock();
-		mCollisionMap[groupA][groupB] = enabled;
-	}
-
-	bool Physics::isCollisionEnabled(UINT64 groupA, UINT64 groupB) const
-	{
-		assert(groupA < CollisionMapSize && groupB < CollisionMapSize);
-
-		mMutex.lock();
-		return mCollisionMap[groupA][groupB];
-	}
-
-	bool Physics::rayCast(const Ray& ray, PhysicsQueryHit& hit, UINT64 layer, float max) const
-	{
-		return rayCast(ray.getOrigin(), ray.getDirection(), hit, layer, max);
-	}
-
-	Vector<PhysicsQueryHit> Physics::rayCastAll(const Ray& ray, UINT64 layer, float max) const
-	{
-		return rayCastAll(ray.getOrigin(), ray.getDirection(), layer, max);
-	}
-
-	bool Physics::rayCastAny(const Ray& ray, UINT64 layer, float max) const
-	{
-		return rayCastAny(ray.getOrigin(), ray.getDirection(), layer, max);
-	}
-
-	Vector<HCollider> rawToComponent(const Vector<Collider*>& raw)
-	{
-		if (raw.empty())
-			return Vector<HCollider>(0);
-
-		Vector<HCollider> output;
-		for (auto& entry : raw)
-		{
-			if (entry == nullptr)
-				continue;
-
-			CCollider* component = (CCollider*)entry->_getOwner(PhysicsOwnerType::Component);
-			if (component == nullptr)
-				continue;
-
-			output.push_back(component->getHandle());
-		}
-
-		return output;
-	}
-
-	Vector<HCollider> Physics::boxOverlap(const AABox& box, const Quaternion& rotation, UINT64 layer) const
-	{
-		return rawToComponent(_boxOverlap(box, rotation, layer));
-	}
-
-	Vector<HCollider> Physics::sphereOverlap(const Sphere& sphere, UINT64 layer) const
-	{
-		return rawToComponent(_sphereOverlap(sphere, layer));
-	}
-
-	Vector<HCollider> Physics::capsuleOverlap(const Capsule& capsule, const Quaternion& rotation, UINT64 layer) const
-	{
-		return rawToComponent(_capsuleOverlap(capsule, rotation, layer));
-	}
-
-	Vector<HCollider> Physics::convexOverlap(const HPhysicsMesh& mesh, const Vector3& position,
-		const Quaternion& rotation, UINT64 layer) const
-	{
-		return rawToComponent(_convexOverlap(mesh, position, rotation, layer));
-	}
-
-	void Physics::registerRigidbody(Rigidbody* body, UINT32 priority)
-	{
-		assert(priority <= MAX_PRIORITY && "Priority value too high");
-
-		if (mRigidbodies.size() <= priority)
-			mRigidbodies.resize(priority + 1);
-
-		UINT32 nextId = (UINT32)mRigidbodies[priority].size();
-		mRigidbodies[priority].push_back(body);
-		body->_setPhysicsId(nextId);
-	}
-
-	void Physics::unregisterRigidbody(UINT32 id, UINT32 priority)
-	{
-		assert(mRigidbodies.size() >= priority);
-
-		auto& rigidbodies = mRigidbodies[priority];
-
-		UINT32 lastId = (UINT32)rigidbodies.size();
-		if (id != lastId)
-		{
-			rigidbodies[id] = rigidbodies[lastId];
-			rigidbodies[id]->_setPhysicsId(id);
-		}
-
-		rigidbodies.erase(rigidbodies.begin() + lastId);
-	}
-
-	void Physics::updatePriority(UINT32 id, UINT32 oldPriority, UINT32 newPriority)
-	{
-		assert(newPriority <= MAX_PRIORITY && "Priority value too high");
-
-		if (oldPriority == newPriority)
-			return;
-
-		assert(mRigidbodies.size() >= oldPriority);
-
-		auto& rigidbodies = mRigidbodies[oldPriority];
-		Rigidbody* rigidbody = rigidbodies[id];
-
-		unregisterRigidbody(id, oldPriority);
-		registerRigidbody(rigidbody, newPriority);
-	}
-
-	Physics& gPhysics()
-	{
-		return Physics::instance();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysics.h"
+#include "BsRigidbody.h"
+#include "BsRay.h"
+#include "BsCCollider.h"
+
+namespace BansheeEngine
+{
+	Physics::Physics(const PHYSICS_INIT_DESC& init)
+	{
+		memset(mCollisionMap, 1, CollisionMapSize * CollisionMapSize * sizeof(bool));
+	}
+
+	void Physics::toggleCollision(UINT64 groupA, UINT64 groupB, bool enabled)
+	{
+		assert(groupA < CollisionMapSize && groupB < CollisionMapSize);
+
+		mMutex.lock();
+		mCollisionMap[groupA][groupB] = enabled;
+	}
+
+	bool Physics::isCollisionEnabled(UINT64 groupA, UINT64 groupB) const
+	{
+		assert(groupA < CollisionMapSize && groupB < CollisionMapSize);
+
+		mMutex.lock();
+		return mCollisionMap[groupA][groupB];
+	}
+
+	bool Physics::rayCast(const Ray& ray, PhysicsQueryHit& hit, UINT64 layer, float max) const
+	{
+		return rayCast(ray.getOrigin(), ray.getDirection(), hit, layer, max);
+	}
+
+	Vector<PhysicsQueryHit> Physics::rayCastAll(const Ray& ray, UINT64 layer, float max) const
+	{
+		return rayCastAll(ray.getOrigin(), ray.getDirection(), layer, max);
+	}
+
+	bool Physics::rayCastAny(const Ray& ray, UINT64 layer, float max) const
+	{
+		return rayCastAny(ray.getOrigin(), ray.getDirection(), layer, max);
+	}
+
+	Vector<HCollider> rawToComponent(const Vector<Collider*>& raw)
+	{
+		if (raw.empty())
+			return Vector<HCollider>(0);
+
+		Vector<HCollider> output;
+		for (auto& entry : raw)
+		{
+			if (entry == nullptr)
+				continue;
+
+			CCollider* component = (CCollider*)entry->_getOwner(PhysicsOwnerType::Component);
+			if (component == nullptr)
+				continue;
+
+			output.push_back(component->getHandle());
+		}
+
+		return output;
+	}
+
+	Vector<HCollider> Physics::boxOverlap(const AABox& box, const Quaternion& rotation, UINT64 layer) const
+	{
+		return rawToComponent(_boxOverlap(box, rotation, layer));
+	}
+
+	Vector<HCollider> Physics::sphereOverlap(const Sphere& sphere, UINT64 layer) const
+	{
+		return rawToComponent(_sphereOverlap(sphere, layer));
+	}
+
+	Vector<HCollider> Physics::capsuleOverlap(const Capsule& capsule, const Quaternion& rotation, UINT64 layer) const
+	{
+		return rawToComponent(_capsuleOverlap(capsule, rotation, layer));
+	}
+
+	Vector<HCollider> Physics::convexOverlap(const HPhysicsMesh& mesh, const Vector3& position,
+		const Quaternion& rotation, UINT64 layer) const
+	{
+		return rawToComponent(_convexOverlap(mesh, position, rotation, layer));
+	}
+
+	void Physics::registerRigidbody(Rigidbody* body, UINT32 priority)
+	{
+		assert(priority <= MAX_PRIORITY && "Priority value too high");
+
+		if (mRigidbodies.size() <= priority)
+			mRigidbodies.resize(priority + 1);
+
+		UINT32 nextId = (UINT32)mRigidbodies[priority].size();
+		mRigidbodies[priority].push_back(body);
+		body->_setPhysicsId(nextId);
+	}
+
+	void Physics::unregisterRigidbody(UINT32 id, UINT32 priority)
+	{
+		assert(mRigidbodies.size() >= priority);
+
+		auto& rigidbodies = mRigidbodies[priority];
+		assert(rigidbodies.size() > 0);
+
+		UINT32 lastId = (UINT32)(rigidbodies.size() - 1);
+		if (id != lastId)
+		{
+			rigidbodies[id] = rigidbodies[lastId];
+			rigidbodies[id]->_setPhysicsId(id);
+		}
+
+		rigidbodies.erase(rigidbodies.begin() + lastId);
+	}
+
+	void Physics::updatePriority(UINT32 id, UINT32 oldPriority, UINT32 newPriority)
+	{
+		assert(newPriority <= MAX_PRIORITY && "Priority value too high");
+
+		if (oldPriority == newPriority)
+			return;
+
+		assert(mRigidbodies.size() >= oldPriority);
+
+		auto& rigidbodies = mRigidbodies[oldPriority];
+		Rigidbody* rigidbody = rigidbodies[id];
+
+		unregisterRigidbody(id, oldPriority);
+		registerRigidbody(rigidbody, newPriority);
+	}
+
+	Physics& gPhysics()
+	{
+		return Physics::instance();
+	}
 }

+ 412 - 407
Source/BansheePhysX/Source/BsPhysXRigidbody.cpp

@@ -1,408 +1,413 @@
-#include "BsPhysXRigidbody.h"
-#include "BsCollider.h"
-#include "BsFPhysXCollider.h"
-#include "BsSceneObject.h"
-#include "BsPhysics.h"
-#include "PxRigidDynamic.h"
-#include "PxScene.h"
-#include "extensions\PxRigidBodyExt.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxForceMode::Enum toPxForceMode(ForceMode mode)
-	{
-		switch(mode)
-		{
-		case ForceMode::Force:
-			return PxForceMode::eFORCE;
-		case ForceMode::Impulse:
-			return PxForceMode::eIMPULSE;
-		case ForceMode::Velocity:
-			return PxForceMode::eVELOCITY_CHANGE;
-		case ForceMode::Acceleration:
-			return PxForceMode::eACCELERATION;
-		}
-
-		return PxForceMode::eFORCE;
-	}
-
-	PxForceMode::Enum toPxForceMode(PointForceMode mode)
-	{
-		switch (mode)
-		{
-		case PointForceMode::Force:
-			return PxForceMode::eFORCE;
-		case PointForceMode::Impulse:
-			return PxForceMode::eIMPULSE;
-		}
-
-		return PxForceMode::eFORCE;
-	}
-
-	PhysXRigidbody::PhysXRigidbody(PxPhysics* physx, PxScene* scene, const HSceneObject& linkedSO)
-		:Rigidbody(linkedSO)
-	{
-		PxTransform tfrm = toPxTransform(linkedSO->getWorldPosition(), linkedSO->getWorldRotation());
-
-		mInternal = physx->createRigidDynamic(tfrm);
-		mInternal->userData = this;
-
-		scene->addActor(*mInternal);
-	}
-
-	PhysXRigidbody::~PhysXRigidbody()
-	{
-		// TODO - Remove from scene? Or is that part of release()?
-		mInternal->release();
-	}
-
-	void PhysXRigidbody::move(const Vector3& position)
-	{
-		PxTransform target;
-		mInternal->getKinematicTarget(target);
-
-		target.p = toPxVector(position);
-
-		mInternal->setKinematicTarget(target);
-	}
-
-	void PhysXRigidbody::rotate(const Quaternion& rotation)
-	{
-		PxTransform target;
-		mInternal->getKinematicTarget(target);
-
-		target.q = toPxQuaternion(rotation);
-
-		mInternal->setKinematicTarget(target);
-	}
-
-	Vector3 PhysXRigidbody::getPosition() const
-	{
-		return fromPxVector(mInternal->getGlobalPose().p);
-	}
-
-	Quaternion PhysXRigidbody::getRotation() const
-	{
-		return fromPxQuaternion(mInternal->getGlobalPose().q);
-	}
-
-	void PhysXRigidbody::setTransform(const Vector3& pos, const Quaternion& rot)
-	{
-		mInternal->setGlobalPose(toPxTransform(pos, rot));
-	}
-
-	void PhysXRigidbody::setMass(float mass)
-	{
-		if(((UINT32)mFlags & (UINT32)Flag::AutoMass) != 0)
-		{
-			LOGWRN("Attempting to set Rigidbody mass, but it has automatic mass calculation turned on.");
-			return;
-		}
-
-		mInternal->setMass(mass);
-	}
-
-	float PhysXRigidbody::getMass() const
-	{
-		return mInternal->getMass();
-	}
-
-	void PhysXRigidbody::setIsKinematic(bool kinematic)
-	{
-		mInternal->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, kinematic);
-	}
-
-	bool PhysXRigidbody::getIsKinematic() const
-	{
-		return ((UINT32)mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) != 0;
-	}
-
-	bool PhysXRigidbody::isSleeping() const
-	{
-		return mInternal->isSleeping();
-	}
-
-	void PhysXRigidbody::sleep()
-	{
-		mInternal->putToSleep();
-	}
-
-	void PhysXRigidbody::wakeUp()
-	{
-		mInternal->wakeUp();
-	}
-
-	void PhysXRigidbody::setSleepThreshold(float threshold)
-	{
-		mInternal->setSleepThreshold(threshold);
-	}
-
-	float PhysXRigidbody::getSleepThreshold() const
-	{
-		return mInternal->getSleepThreshold();
-	}
-
-	void PhysXRigidbody::setUseGravity(bool gravity)
-	{
-		mInternal->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !gravity);
-	}
-
-	bool PhysXRigidbody::getUseGravity() const
-	{
-		return ((UINT32)mInternal->getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == 0;
-	}
-
-	void PhysXRigidbody::setVelocity(const Vector3& velocity)
-	{
-		mInternal->setLinearVelocity(toPxVector(velocity));
-	}
-
-	Vector3 PhysXRigidbody::getVelocity() const
-	{
-		return fromPxVector(mInternal->getLinearVelocity());
-	}
-
-	void PhysXRigidbody::setAngularVelocity(const Vector3& velocity)
-	{
-		mInternal->setAngularVelocity(toPxVector(velocity));
-	}
-
-	Vector3 PhysXRigidbody::getAngularVelocity() const
-	{
-		return fromPxVector(mInternal->getAngularVelocity());
-	}
-
-	void PhysXRigidbody::setDrag(float drag)
-	{
-		mInternal->setLinearDamping(drag);
-	}
-
-	float PhysXRigidbody::getDrag() const
-	{
-		return mInternal->getLinearDamping();
-	}
-
-	void PhysXRigidbody::setAngularDrag(float drag)
-	{
-		mInternal->setAngularDamping(drag);
-	}
-
-	float PhysXRigidbody::getAngularDrag() const
-	{
-		return mInternal->getAngularDamping();
-	}
-
-	void PhysXRigidbody::setInertiaTensor(const Vector3& tensor)
-	{
-		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) != 0)
-		{
-			LOGWRN("Attempting to set Rigidbody inertia tensor, but it has automatic tensor calculation turned on.");
-			return;
-		}
-
-		mInternal->setMassSpaceInertiaTensor(toPxVector(tensor));
-	}
-
-	Vector3 PhysXRigidbody::getInertiaTensor() const
-	{
-		return fromPxVector(mInternal->getMassSpaceInertiaTensor());
-	}
-
-	void PhysXRigidbody::setMaxAngularVelocity(float maxVelocity)
-	{
-		mInternal->setMaxAngularVelocity(maxVelocity);
-	}
-
-	float PhysXRigidbody::getMaxAngularVelocity() const
-	{
-		return mInternal->getMaxAngularVelocity();
-	}
-
-	void PhysXRigidbody::setCenterOfMass(const Vector3& position, const Quaternion& rotation)
-	{
-		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) != 0)
-		{
-			LOGWRN("Attempting to set Rigidbody center of mass, but it has automatic tensor calculation turned on.");
-			return;
-		}
-
-		mInternal->setCMassLocalPose(toPxTransform(position, rotation));
-	}
-
-	Vector3 PhysXRigidbody::getCenterOfMassPosition() const
-	{
-		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
-		return fromPxVector(cMassTfrm.p);
-	}
-
-	Quaternion PhysXRigidbody::getCenterOfMassRotation() const
-	{
-		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
-		return fromPxQuaternion(cMassTfrm.q);
-	}
-
-	void PhysXRigidbody::setPositionSolverCount(UINT32 count)
-	{
-		mInternal->setSolverIterationCounts(std::max(1U, count), getVelocitySolverCount());
-	}
-
-	UINT32 PhysXRigidbody::getPositionSolverCount() const
-	{
-		UINT32 posCount = 1;
-		UINT32 velCount = 1;
-
-		mInternal->getSolverIterationCounts(posCount, velCount);
-		return posCount;
-	}
-
-	void PhysXRigidbody::setVelocitySolverCount(UINT32 count)
-	{
-		mInternal->setSolverIterationCounts(getPositionSolverCount(), std::max(1U, count));
-	}
-
-	UINT32 PhysXRigidbody::getVelocitySolverCount() const
-	{
-		UINT32 posCount = 1;
-		UINT32 velCount = 1;
-
-		mInternal->getSolverIterationCounts(posCount, velCount);
-		return velCount;
-	}
-
-	void PhysXRigidbody::setFlags(Flag flags)
-	{
-		bool ccdEnabledOld = mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eENABLE_CCD;
-		bool ccdEnabledNew = ((UINT32)flags & (UINT32)Flag::CCD) != 0;
-		
-		if(ccdEnabledOld != ccdEnabledNew)
-		{
-			if(ccdEnabledNew)
-			{
-				if (!gPhysics().hasFlag(PhysicsFlag::CCD_Enable))
-					LOGWRN("Enabling CCD on a Rigidbody but CCD is not enabled globally.");
-			}
-
-			mInternal->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, ccdEnabledNew);
-
-			// Enable/disable CCD on shapes so the filter can handle them properly
-			UINT32 numShapes = mInternal->getNbShapes();
-			PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
-
-			mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
-
-			for (UINT32 i = 0; i < numShapes; i++)
-			{
-				Collider* collider = (Collider*)shapes[i]->userData;
-				collider->_getInternal()->_setCCD(ccdEnabledNew);
-			}
-		}
-
-		Rigidbody::setFlags(flags);
-	}
-
-	void PhysXRigidbody::addForce(const Vector3& force, ForceMode mode)
-	{
-		mInternal->addForce(toPxVector(force), toPxForceMode(mode));
-	}
-
-	void PhysXRigidbody::addTorque(const Vector3& force, ForceMode mode)
-	{
-		mInternal->addTorque(toPxVector(force), toPxForceMode(mode));
-	}
-
-	void PhysXRigidbody::addForceAtPoint(const Vector3& force, const Vector3& position, PointForceMode mode)
-	{
-		const PxVec3& pxForce = toPxVector(force);
-		const PxVec3& pxPos = toPxVector(position);
-
-		const PxTransform globalPose = mInternal->getGlobalPose();
-		PxVec3 centerOfMass = globalPose.transform(mInternal->getCMassLocalPose().p);
-
-		PxForceMode::Enum pxMode = toPxForceMode(mode);
-
-		PxVec3 torque = (pxPos - centerOfMass).cross(pxForce);
-		mInternal->addForce(pxForce, pxMode);
-		mInternal->addTorque(torque, pxMode);
-	}
-
-	Vector3 PhysXRigidbody::getVelocityAtPoint(const Vector3& point) const
-	{
-		const PxVec3& pxPoint = toPxVector(point);
-
-		const PxTransform globalPose = mInternal->getGlobalPose();
-		const PxVec3 centerOfMass = globalPose.transform(mInternal->getCMassLocalPose().p);
-		const PxVec3 rpoint = pxPoint - centerOfMass;
-
-		PxVec3 velocity = mInternal->getLinearVelocity();
-		velocity += mInternal->getAngularVelocity().cross(rpoint);
-
-		return fromPxVector(velocity);
-	}
-
-	void PhysXRigidbody::updateMassDistribution() 
-	{
-		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) == 0)
-			return;
-
-		if (((UINT32)mFlags & (UINT32)Flag::AutoMass) == 0)
-		{
-			PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, mInternal->getMass());
-		}
-		else
-		{
-			UINT32 numShapes = mInternal->getNbShapes();
-
-			PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
-			mInternal->getShapes(shapes, numShapes);
-
-			float* masses = (float*)bs_stack_alloc(sizeof(float) * numShapes);
-			for (UINT32 i = 0; i < numShapes; i++)
-				masses[i] = ((Collider*)shapes[i]->userData)->getMass();
-
-			PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, masses, numShapes);
-
-			bs_stack_free(masses);
-			bs_stack_free(shapes);
-		}
-	}
-
-	void PhysXRigidbody::addCollider(FCollider* collider)
-	{
-		if (collider == nullptr)
-			return;
-
-		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
-		physxCollider->_setCCD(((UINT32)mFlags & (UINT32)Flag::CCD) != 0);
-
-		mInternal->attachShape(*physxCollider->_getShape());
-	}
-
-	void PhysXRigidbody::removeCollider(FCollider* collider)
-	{
-		if (collider == nullptr)
-			return;
-
-		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
-		physxCollider->_setCCD(false);
-
-		mInternal->detachShape(*physxCollider->_getShape());
-	}
-
-	void PhysXRigidbody::removeColliders()
-	{
-		UINT32 numShapes = mInternal->getNbShapes();
-		PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
-
-		mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
-
-		for (UINT32 i = 0; i < numShapes; i++)
-		{
-			Collider* collider = (Collider*)shapes[i]->userData;
-			collider->_getInternal()->_setCCD(false);
-
-			mInternal->detachShape(*shapes[i]);
-		}
-	}
+#include "BsPhysXRigidbody.h"
+#include "BsCollider.h"
+#include "BsFPhysXCollider.h"
+#include "BsSceneObject.h"
+#include "BsPhysics.h"
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+#include "extensions\PxRigidBodyExt.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxForceMode::Enum toPxForceMode(ForceMode mode)
+	{
+		switch(mode)
+		{
+		case ForceMode::Force:
+			return PxForceMode::eFORCE;
+		case ForceMode::Impulse:
+			return PxForceMode::eIMPULSE;
+		case ForceMode::Velocity:
+			return PxForceMode::eVELOCITY_CHANGE;
+		case ForceMode::Acceleration:
+			return PxForceMode::eACCELERATION;
+		}
+
+		return PxForceMode::eFORCE;
+	}
+
+	PxForceMode::Enum toPxForceMode(PointForceMode mode)
+	{
+		switch (mode)
+		{
+		case PointForceMode::Force:
+			return PxForceMode::eFORCE;
+		case PointForceMode::Impulse:
+			return PxForceMode::eIMPULSE;
+		}
+
+		return PxForceMode::eFORCE;
+	}
+
+	PhysXRigidbody::PhysXRigidbody(PxPhysics* physx, PxScene* scene, const HSceneObject& linkedSO)
+		:Rigidbody(linkedSO)
+	{
+		PxTransform tfrm = toPxTransform(linkedSO->getWorldPosition(), linkedSO->getWorldRotation());
+
+		mInternal = physx->createRigidDynamic(tfrm);
+		mInternal->userData = this;
+
+		scene->addActor(*mInternal);
+	}
+
+	PhysXRigidbody::~PhysXRigidbody()
+	{
+		// TODO - Remove from scene? Or is that part of release()?
+		mInternal->release();
+	}
+
+	void PhysXRigidbody::move(const Vector3& position)
+	{
+		PxTransform target;
+		mInternal->getKinematicTarget(target);
+
+		target.p = toPxVector(position);
+
+		mInternal->setKinematicTarget(target);
+	}
+
+	void PhysXRigidbody::rotate(const Quaternion& rotation)
+	{
+		PxTransform target;
+		mInternal->getKinematicTarget(target);
+
+		target.q = toPxQuaternion(rotation);
+
+		mInternal->setKinematicTarget(target);
+	}
+
+	Vector3 PhysXRigidbody::getPosition() const
+	{
+		return fromPxVector(mInternal->getGlobalPose().p);
+	}
+
+	Quaternion PhysXRigidbody::getRotation() const
+	{
+		return fromPxQuaternion(mInternal->getGlobalPose().q);
+	}
+
+	void PhysXRigidbody::setTransform(const Vector3& pos, const Quaternion& rot)
+	{
+		mInternal->setGlobalPose(toPxTransform(pos, rot));
+	}
+
+	void PhysXRigidbody::setMass(float mass)
+	{
+		if(((UINT32)mFlags & (UINT32)Flag::AutoMass) != 0)
+		{
+			LOGWRN("Attempting to set Rigidbody mass, but it has automatic mass calculation turned on.");
+			return;
+		}
+
+		mInternal->setMass(mass);
+	}
+
+	float PhysXRigidbody::getMass() const
+	{
+		return mInternal->getMass();
+	}
+
+	void PhysXRigidbody::setIsKinematic(bool kinematic)
+	{
+		mInternal->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, kinematic);
+	}
+
+	bool PhysXRigidbody::getIsKinematic() const
+	{
+		return ((UINT32)mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) != 0;
+	}
+
+	bool PhysXRigidbody::isSleeping() const
+	{
+		return mInternal->isSleeping();
+	}
+
+	void PhysXRigidbody::sleep()
+	{
+		mInternal->putToSleep();
+	}
+
+	void PhysXRigidbody::wakeUp()
+	{
+		mInternal->wakeUp();
+	}
+
+	void PhysXRigidbody::setSleepThreshold(float threshold)
+	{
+		mInternal->setSleepThreshold(threshold);
+	}
+
+	float PhysXRigidbody::getSleepThreshold() const
+	{
+		return mInternal->getSleepThreshold();
+	}
+
+	void PhysXRigidbody::setUseGravity(bool gravity)
+	{
+		mInternal->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !gravity);
+	}
+
+	bool PhysXRigidbody::getUseGravity() const
+	{
+		return ((UINT32)mInternal->getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == 0;
+	}
+
+	void PhysXRigidbody::setVelocity(const Vector3& velocity)
+	{
+		mInternal->setLinearVelocity(toPxVector(velocity));
+	}
+
+	Vector3 PhysXRigidbody::getVelocity() const
+	{
+		return fromPxVector(mInternal->getLinearVelocity());
+	}
+
+	void PhysXRigidbody::setAngularVelocity(const Vector3& velocity)
+	{
+		mInternal->setAngularVelocity(toPxVector(velocity));
+	}
+
+	Vector3 PhysXRigidbody::getAngularVelocity() const
+	{
+		return fromPxVector(mInternal->getAngularVelocity());
+	}
+
+	void PhysXRigidbody::setDrag(float drag)
+	{
+		mInternal->setLinearDamping(drag);
+	}
+
+	float PhysXRigidbody::getDrag() const
+	{
+		return mInternal->getLinearDamping();
+	}
+
+	void PhysXRigidbody::setAngularDrag(float drag)
+	{
+		mInternal->setAngularDamping(drag);
+	}
+
+	float PhysXRigidbody::getAngularDrag() const
+	{
+		return mInternal->getAngularDamping();
+	}
+
+	void PhysXRigidbody::setInertiaTensor(const Vector3& tensor)
+	{
+		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) != 0)
+		{
+			LOGWRN("Attempting to set Rigidbody inertia tensor, but it has automatic tensor calculation turned on.");
+			return;
+		}
+
+		mInternal->setMassSpaceInertiaTensor(toPxVector(tensor));
+	}
+
+	Vector3 PhysXRigidbody::getInertiaTensor() const
+	{
+		return fromPxVector(mInternal->getMassSpaceInertiaTensor());
+	}
+
+	void PhysXRigidbody::setMaxAngularVelocity(float maxVelocity)
+	{
+		mInternal->setMaxAngularVelocity(maxVelocity);
+	}
+
+	float PhysXRigidbody::getMaxAngularVelocity() const
+	{
+		return mInternal->getMaxAngularVelocity();
+	}
+
+	void PhysXRigidbody::setCenterOfMass(const Vector3& position, const Quaternion& rotation)
+	{
+		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) != 0)
+		{
+			LOGWRN("Attempting to set Rigidbody center of mass, but it has automatic tensor calculation turned on.");
+			return;
+		}
+
+		mInternal->setCMassLocalPose(toPxTransform(position, rotation));
+	}
+
+	Vector3 PhysXRigidbody::getCenterOfMassPosition() const
+	{
+		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
+		return fromPxVector(cMassTfrm.p);
+	}
+
+	Quaternion PhysXRigidbody::getCenterOfMassRotation() const
+	{
+		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
+		return fromPxQuaternion(cMassTfrm.q);
+	}
+
+	void PhysXRigidbody::setPositionSolverCount(UINT32 count)
+	{
+		mInternal->setSolverIterationCounts(std::max(1U, count), getVelocitySolverCount());
+	}
+
+	UINT32 PhysXRigidbody::getPositionSolverCount() const
+	{
+		UINT32 posCount = 1;
+		UINT32 velCount = 1;
+
+		mInternal->getSolverIterationCounts(posCount, velCount);
+		return posCount;
+	}
+
+	void PhysXRigidbody::setVelocitySolverCount(UINT32 count)
+	{
+		mInternal->setSolverIterationCounts(getPositionSolverCount(), std::max(1U, count));
+	}
+
+	UINT32 PhysXRigidbody::getVelocitySolverCount() const
+	{
+		UINT32 posCount = 1;
+		UINT32 velCount = 1;
+
+		mInternal->getSolverIterationCounts(posCount, velCount);
+		return velCount;
+	}
+
+	void PhysXRigidbody::setFlags(Flag flags)
+	{
+		bool ccdEnabledOld = mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eENABLE_CCD;
+		bool ccdEnabledNew = ((UINT32)flags & (UINT32)Flag::CCD) != 0;
+		
+		if(ccdEnabledOld != ccdEnabledNew)
+		{
+			if(ccdEnabledNew)
+			{
+				if (!gPhysics().hasFlag(PhysicsFlag::CCD_Enable))
+					LOGWRN("Enabling CCD on a Rigidbody but CCD is not enabled globally.");
+			}
+
+			mInternal->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, ccdEnabledNew);
+
+			// Enable/disable CCD on shapes so the filter can handle them properly
+			UINT32 numShapes = mInternal->getNbShapes();
+			PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
+
+			mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
+
+			for (UINT32 i = 0; i < numShapes; i++)
+			{
+				Collider* collider = (Collider*)shapes[i]->userData;
+				collider->_getInternal()->_setCCD(ccdEnabledNew);
+			}
+		}
+
+		Rigidbody::setFlags(flags);
+	}
+
+	void PhysXRigidbody::addForce(const Vector3& force, ForceMode mode)
+	{
+		mInternal->addForce(toPxVector(force), toPxForceMode(mode));
+	}
+
+	void PhysXRigidbody::addTorque(const Vector3& force, ForceMode mode)
+	{
+		mInternal->addTorque(toPxVector(force), toPxForceMode(mode));
+	}
+
+	void PhysXRigidbody::addForceAtPoint(const Vector3& force, const Vector3& position, PointForceMode mode)
+	{
+		const PxVec3& pxForce = toPxVector(force);
+		const PxVec3& pxPos = toPxVector(position);
+
+		const PxTransform globalPose = mInternal->getGlobalPose();
+		PxVec3 centerOfMass = globalPose.transform(mInternal->getCMassLocalPose().p);
+
+		PxForceMode::Enum pxMode = toPxForceMode(mode);
+
+		PxVec3 torque = (pxPos - centerOfMass).cross(pxForce);
+		mInternal->addForce(pxForce, pxMode);
+		mInternal->addTorque(torque, pxMode);
+	}
+
+	Vector3 PhysXRigidbody::getVelocityAtPoint(const Vector3& point) const
+	{
+		const PxVec3& pxPoint = toPxVector(point);
+
+		const PxTransform globalPose = mInternal->getGlobalPose();
+		const PxVec3 centerOfMass = globalPose.transform(mInternal->getCMassLocalPose().p);
+		const PxVec3 rpoint = pxPoint - centerOfMass;
+
+		PxVec3 velocity = mInternal->getLinearVelocity();
+		velocity += mInternal->getAngularVelocity().cross(rpoint);
+
+		return fromPxVector(velocity);
+	}
+
+	void PhysXRigidbody::updateMassDistribution() 
+	{
+		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) == 0)
+			return;
+
+		if (((UINT32)mFlags & (UINT32)Flag::AutoMass) == 0)
+		{
+			PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, mInternal->getMass());
+		}
+		else
+		{
+			UINT32 numShapes = mInternal->getNbShapes();
+			if (numShapes == 0)
+			{
+				PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, mInternal->getMass());
+				return;
+			}
+
+			PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
+			mInternal->getShapes(shapes, numShapes);
+
+			float* masses = (float*)bs_stack_alloc(sizeof(float) * numShapes);
+			for (UINT32 i = 0; i < numShapes; i++)
+				masses[i] = ((Collider*)shapes[i]->userData)->getMass();
+
+			PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, masses, numShapes);
+
+			bs_stack_free(masses);
+			bs_stack_free(shapes);
+		}
+	}
+
+	void PhysXRigidbody::addCollider(FCollider* collider)
+	{
+		if (collider == nullptr)
+			return;
+
+		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		physxCollider->_setCCD(((UINT32)mFlags & (UINT32)Flag::CCD) != 0);
+
+		mInternal->attachShape(*physxCollider->_getShape());
+	}
+
+	void PhysXRigidbody::removeCollider(FCollider* collider)
+	{
+		if (collider == nullptr)
+			return;
+
+		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		physxCollider->_setCCD(false);
+
+		mInternal->detachShape(*physxCollider->_getShape());
+	}
+
+	void PhysXRigidbody::removeColliders()
+	{
+		UINT32 numShapes = mInternal->getNbShapes();
+		PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
+
+		mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
+
+		for (UINT32 i = 0; i < numShapes; i++)
+		{
+			Collider* collider = (Collider*)shapes[i]->userData;
+			collider->_getInternal()->_setCCD(false);
+
+			mInternal->detachShape(*shapes[i]);
+		}
+	}
 }

+ 151 - 151
Source/MBansheeEditor/Inspectors/RigidbodyInspector.cs

@@ -1,152 +1,152 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Renders an inspector for the <see cref="Rigidbody"/> component.
-    /// </summary>
-    [CustomInspector(typeof(Rigidbody))]
-    internal class RigidbodyInspector : Inspector
-    {
-        private GUIToggleField kinematicField = new GUIToggleField(new LocEdString("Kinematic"));
-        private GUIToggleField applyGravityField = new GUIToggleField(new LocEdString("Apply gravity"));
-        private GUIToggleField automaticMassField = new GUIToggleField(new LocEdString("Calculate mass"));
-        private GUIFloatField massField = new GUIFloatField("Mass");
-        private GUIFloatField linearDragField = new GUIFloatField("Linear drag");
-        private GUIFloatField angularDragField = new GUIFloatField("Angular drag");
-        private GUIEnumField interpolationModeField = new GUIEnumField(typeof (RigidbodyInterpolationMode),
-            new LocEdString("Interpolation mode"));
-        private GUIEnumField reportModeField = new GUIEnumField(typeof (CollisionReportMode),
-            new LocEdString("Collision report mode"));
-        private GUIToggleField ccdField = new GUIToggleField("Continous");
-
-        private InspectableState modifyState;
-
-        /// <inheritdoc/>
-        protected internal override void Initialize()
-        {
-            BuildGUI();
-        }
-
-        /// <inheritdoc/>
-        protected internal override InspectableState Refresh()
-        {
-            Rigidbody body = InspectedObject as Rigidbody;
-            if (body == null)
-                return InspectableState.NotModified;
-
-            kinematicField.Value = body.Kinematic;
-            applyGravityField.Value = body.UseGravity;
-            automaticMassField.Value = (body.Flags & RigidbodyFlag.AutoMass) != 0;
-            massField.Value = body.Mass;
-            linearDragField.Value = body.Drag;
-            angularDragField.Value = body.AngularDrag;
-            interpolationModeField.Value = (ulong)body.InterpolationMode;
-            reportModeField.Value = (ulong) body.CollisionReportMode;
-            ccdField.Value = (body.Flags & RigidbodyFlag.CCD) != 0;
-
-            massField.Active = (body.Flags & RigidbodyFlag.AutoMass) == 0;
-            
-            InspectableState oldState = modifyState;
-            if (modifyState.HasFlag(InspectableState.Modified))
-                modifyState = InspectableState.NotModified;
-
-            return oldState;
-        }
-
-        /// <summary>
-        /// Recreates all the GUI elements used by this inspector.
-        /// </summary>
-        private void BuildGUI()
-        {
-            Rigidbody body = InspectedObject as Rigidbody;
-            if (body == null)
-                return;
-
-            kinematicField.OnChanged += x => { body.Kinematic = x; MarkAsModified(); ConfirmModify(); };
-            applyGravityField.OnChanged += x => { body.UseGravity = x; MarkAsModified(); ConfirmModify(); };
-            automaticMassField.OnChanged += x =>
-            {
-                if (x)
-                    body.Flags |= RigidbodyFlag.AutoMass;
-                else
-                    body.Flags &= ~RigidbodyFlag.AutoMass;
-
-                massField.Active = !x;
-
-                MarkAsModified();
-                ConfirmModify();
-            };
-
-            massField.OnChanged += x => { body.Mass = x; MarkAsModified(); };
-            massField.OnConfirmed += ConfirmModify;
-            massField.OnFocusLost += ConfirmModify;
-
-            linearDragField.OnChanged += x => { body.Drag = x; MarkAsModified(); };
-            linearDragField.OnConfirmed += ConfirmModify;
-            linearDragField.OnFocusLost += ConfirmModify;
-
-            angularDragField.OnChanged += x => { body.AngularDrag = x; MarkAsModified(); };
-            angularDragField.OnConfirmed += ConfirmModify;
-            angularDragField.OnFocusLost += ConfirmModify;
-
-            interpolationModeField.OnSelectionChanged += x =>
-            {
-                body.InterpolationMode = (RigidbodyInterpolationMode)x;
-
-                MarkAsModified();
-                ConfirmModify();
-            };
-
-            reportModeField.OnSelectionChanged += x =>
-            {
-                body.CollisionReportMode = (CollisionReportMode) x;
-
-                MarkAsModified();
-                ConfirmModify();
-            };
-
-            ccdField.OnChanged += x =>
-            {
-                if (x)
-                    body.Flags |= RigidbodyFlag.CCD;
-                else
-                    body.Flags &= ~RigidbodyFlag.CCD;
-
-                MarkAsModified();
-                ConfirmModify();
-            };
-
-            massField.Active = (body.Flags & RigidbodyFlag.AutoMass) == 0;
-
-            Layout.AddElement(kinematicField);
-            Layout.AddElement(applyGravityField);
-            Layout.AddElement(automaticMassField);
-            Layout.AddElement(massField);
-            Layout.AddElement(linearDragField);
-            Layout.AddElement(angularDragField);
-            Layout.AddElement(interpolationModeField);
-            Layout.AddElement(reportModeField);
-            Layout.AddElement(ccdField);
-        }
-        
-        /// <summary>
-        /// Marks the contents of the inspector as modified.
-        /// </summary>
-        protected void MarkAsModified()
-        {
-            modifyState |= InspectableState.ModifyInProgress;
-        }
-
-        /// <summary>
-        /// Confirms any queued modifications.
-        /// </summary>
-        protected void ConfirmModify()
-        {
-            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
-                modifyState |= InspectableState.Modified;
-        }
-    }
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="Rigidbody"/> component.
+    /// </summary>
+    [CustomInspector(typeof(Rigidbody))]
+    internal class RigidbodyInspector : Inspector
+    {
+        private GUIToggleField kinematicField = new GUIToggleField(new LocEdString("Kinematic"));
+        private GUIToggleField applyGravityField = new GUIToggleField(new LocEdString("Apply gravity"));
+        private GUIToggleField automaticMassField = new GUIToggleField(new LocEdString("Calculate mass"));
+        private GUIFloatField massField = new GUIFloatField(new LocEdString("Mass"));
+        private GUIFloatField linearDragField = new GUIFloatField(new LocEdString("Linear drag"));
+        private GUIFloatField angularDragField = new GUIFloatField(new LocEdString("Angular drag"));
+        private GUIEnumField interpolationModeField = new GUIEnumField(typeof (RigidbodyInterpolationMode),
+            new LocEdString("Interpolation mode"));
+        private GUIEnumField reportModeField = new GUIEnumField(typeof (CollisionReportMode),
+            new LocEdString("Collision report mode"));
+        private GUIToggleField ccdField = new GUIToggleField(new LocEdString("Continous"));
+
+        private InspectableState modifyState;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            BuildGUI();
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            Rigidbody body = InspectedObject as Rigidbody;
+            if (body == null)
+                return InspectableState.NotModified;
+
+            kinematicField.Value = body.Kinematic;
+            applyGravityField.Value = body.UseGravity;
+            automaticMassField.Value = (body.Flags & RigidbodyFlag.AutoMass) != 0;
+            massField.Value = body.Mass;
+            linearDragField.Value = body.Drag;
+            angularDragField.Value = body.AngularDrag;
+            interpolationModeField.Value = (ulong)body.InterpolationMode;
+            reportModeField.Value = (ulong) body.CollisionReportMode;
+            ccdField.Value = (body.Flags & RigidbodyFlag.CCD) != 0;
+
+            massField.Active = (body.Flags & RigidbodyFlag.AutoMass) == 0;
+            
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Recreates all the GUI elements used by this inspector.
+        /// </summary>
+        private void BuildGUI()
+        {
+            Rigidbody body = InspectedObject as Rigidbody;
+            if (body == null)
+                return;
+
+            kinematicField.OnChanged += x => { body.Kinematic = x; MarkAsModified(); ConfirmModify(); };
+            applyGravityField.OnChanged += x => { body.UseGravity = x; MarkAsModified(); ConfirmModify(); };
+            automaticMassField.OnChanged += x =>
+            {
+                if (x)
+                    body.Flags |= RigidbodyFlag.AutoMass;
+                else
+                    body.Flags &= ~RigidbodyFlag.AutoMass;
+
+                massField.Active = !x;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            massField.OnChanged += x => { body.Mass = x; MarkAsModified(); };
+            massField.OnConfirmed += ConfirmModify;
+            massField.OnFocusLost += ConfirmModify;
+
+            linearDragField.OnChanged += x => { body.Drag = x; MarkAsModified(); };
+            linearDragField.OnConfirmed += ConfirmModify;
+            linearDragField.OnFocusLost += ConfirmModify;
+
+            angularDragField.OnChanged += x => { body.AngularDrag = x; MarkAsModified(); };
+            angularDragField.OnConfirmed += ConfirmModify;
+            angularDragField.OnFocusLost += ConfirmModify;
+
+            interpolationModeField.OnSelectionChanged += x =>
+            {
+                body.InterpolationMode = (RigidbodyInterpolationMode)x;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            reportModeField.OnSelectionChanged += x =>
+            {
+                body.CollisionReportMode = (CollisionReportMode) x;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            ccdField.OnChanged += x =>
+            {
+                if (x)
+                    body.Flags |= RigidbodyFlag.CCD;
+                else
+                    body.Flags &= ~RigidbodyFlag.CCD;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            massField.Active = (body.Flags & RigidbodyFlag.AutoMass) == 0;
+
+            Layout.AddElement(kinematicField);
+            Layout.AddElement(applyGravityField);
+            Layout.AddElement(automaticMassField);
+            Layout.AddElement(massField);
+            Layout.AddElement(linearDragField);
+            Layout.AddElement(angularDragField);
+            Layout.AddElement(interpolationModeField);
+            Layout.AddElement(reportModeField);
+            Layout.AddElement(ccdField);
+        }
+        
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifyState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
+                modifyState |= InspectableState.Modified;
+        }
+    }
 }

+ 484 - 490
Source/MBansheeEngine/Physics/CharacterController.cs

@@ -1,491 +1,485 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Special physics controller meant to be used for game characters. Uses the "slide-and-collide" physics instead of
-    /// of the standard physics model to handle various issues with manually moving kinematic objects.Uses a capsule to
-    /// represent the character's bounds. 
-    /// </summary>
-    public sealed class CharacterController : Component
-    {
-        internal NativeCharacterController native;
-
-        [SerializeField]
-        internal SerializableData serializableData = new SerializableData();
-
-        /// <summary>
-        /// Triggered when the controller hits a collider.
-        /// </summary>
-        public event Action<ControllerColliderCollision> OnColliderHit;
-
-        /// <summary>
-        /// Triggered when the controller hits another character controller.
-        /// </summary>
-        public event Action<ControllerControllerCollision> OnControllerHit;
-
-        /// <summary>
-        /// Position of the bottom of the controller. Position takes contact offset into account. Changing this value will 
-        /// teleport the character to the location. Use <see cref="Move"/> for movement that includes physics.
-        /// </summary>
-        public Vector3 FootPosition
-        {
-            get
-            {
-                if (native != null)
-                    return native.FootPosition;
-
-                return Vector3.Zero;
-            }
-            set
-            {
-                if (native != null)
-                {
-                    native.FootPosition = value;
-                    UpdatePositionFromController();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Radius of the controller capsule.
-        /// </summary>
-        public float Radius
-        {
-            get { return serializableData.radius; }
-            set
-            {
-                serializableData.radius = value;
-
-                if(native != null)
-                    UpdateDimensions();
-            }
-        }
-
-        /// <summary>
-        /// Height between the centers of the two spheres of the controller capsule.
-        /// </summary>
-        public float Height
-        {
-            get { return serializableData.height; }
-            set
-            {
-                serializableData.height = value;
-
-                if(native != null)
-                    UpdateDimensions();
-            }
-        }
-
-        /// <summary>
-        /// Up direction of capsule. Determines capsule orientation.
-        /// </summary>
-        public Vector3 Up
-        {
-            get { return serializableData.up; }
-            set
-            {
-                serializableData.up = value;
-
-                if (native != null)
-                    native.Up = value;
-            }
-        }
-
-        /// <summary>
-        /// Controls what happens when character encounters a height higher than its step offset. 
-        /// </summary>
-        public CharacterClimbingMode ClimbingMode
-        {
-            get { return serializableData.climbingMode; }
-            set
-            {
-                serializableData.climbingMode = value;
-
-                if (native != null)
-                    native.ClimbingMode = value;
-            }
-        }
-
-        /// <summary>
-        /// Controls what happens when character encounters a slope higher than its slope offset. 
-        /// </summary>
-        public CharacterNonWalkableMode NonWalkableMode
-        {
-            get { return serializableData.nonWalkableMode; }
-            set
-            {
-                serializableData.nonWalkableMode = value;
-
-                if (native != null)
-                    native.NonWalkableMode = value;
-            }
-        }
-
-        /// <summary>
-        /// Represents minimum distance that the character will move during a call to <see cref="Move"/>. This is used to
-        /// stop the recursive motion algorithm when the remaining distance is too small.
-        /// </summary>
-        public float MinMoveDistance
-        {
-            get { return serializableData.minMoveDistance; }
-            set
-            {
-                serializableData.minMoveDistance = value;
-
-                if (native != null)
-                    native.MinMoveDistance = value;
-            }
-        }
-
-        /// <summary>
-        /// Contact offset specifies a skin around the object within which contacts will be generated. It should be a small
-        /// positive non-zero value.
-        /// </summary>
-        public float ContactOffset
-        {
-            get { return serializableData.contactOffset; }
-            set
-            {
-                serializableData.contactOffset = value;
-
-                if (native != null)
-                    native.ContactOffset = value;
-            }
-        }
-
-        /// <summary>
-        /// Controls which obstacles will the character be able to automatically step over without being stopped. This is 
-        /// the height of the maximum obstacle that will be stepped over (with exceptions, <see cref="ClimbingMode"/>).
-        /// </summary>
-        public float StepOffset
-        {
-            get { return serializableData.stepOffset; }
-            set
-            {
-                serializableData.stepOffset = value;
-
-                if (native != null)
-                    native.StepOffset = value;
-            }
-        }
-
-        /// <summary>
-        /// Controls which slopes should the character consider too steep and won't be able to move over. 
-        /// <see cref="NonWalkableMode"/> for more information.
-        /// </summary>
-        public Radian SlopeLimit
-        {
-            get { return serializableData.slopeLimit; }
-            set
-            {
-                serializableData.slopeLimit = value;
-
-                if (native != null)
-                    native.SlopeLimit = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines what can the controller collide with. Objects that are allowed to collide with this object must have
-        /// the same bits set in their own layers.
-        /// </summary>
-        public ulong Layer
-        {
-            get { return serializableData.layer; }
-            set
-            {
-                serializableData.layer = value;
-
-                if (native != null)
-                    native.Layer = value;
-            }
-        }
-
-        /// <summary>
-        /// Moves the controller in the specified direction by the specified amount, while interacting with surrounding
-        /// geometry.Returns flags signaling where collision occurred after the movement.
-        /// 
-        /// Does not account for gravity, you must apply it manually.
-        /// </summary>
-        /// <param name="position">Position to move the controller to, in world space.</param>
-        public void Move(Vector3 position)
-        {
-            if (native == null)
-                return;
-
-            native.Move(position);
-            UpdatePositionFromController();
-        }
-
-        /// <summary>
-        /// Triggered when the controller hits a collider.
-        /// </summary>
-        /// <param name="data">Data about the collision.</param>
-        internal void DoOnColliderHit(ControllerColliderCollision data)
-        {
-            if (OnColliderHit != null)
-                OnColliderHit(data);
-        }
-
-        /// <summary>
-        /// Triggered when the controller hits another character controller.
-        /// </summary>
-        /// <param name="data">Data about the collision.</param>
-        internal void DoOnControllerHit(ControllerControllerCollision data)
-        {
-            if (OnControllerHit != null)
-                OnControllerHit(data);
-        }
-
-        private void OnInitialize()
-        {
-            NotifyFlags = TransformChangedFlags.Transform;
-        }
-
-        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 || native == null)
-                return;
-
-            native.Position = SceneObject.Position;
-        }
-
-        /// <summary>
-        /// Updates the position by copying it from the controller to the component's scene object.
-        /// </summary>
-        private void UpdatePositionFromController()
-        {
-            NotifyFlags = 0;
-            SceneObject.Position = native.Position;
-            NotifyFlags = TransformChangedFlags.Transform;
-        }
-
-        /// <summary>
-        /// Updates the dimensions of the controller by taking account scale of the parent scene object.
-        /// </summary>
-        private void UpdateDimensions()
-        {
-            Vector3 scale = SceneObject.Scale;
-            float height = serializableData.height * MathEx.Abs(scale.y);
-            float radius = serializableData.radius * MathEx.Abs(MathEx.Max(scale.x, scale.z));
-
-            native.Height = height;
-            native.Radius = radius;
-        }
-
-        /// <summary>
-        /// Restores the internal character controller representation and initializes it with data stored by the component.
-        /// </summary>
-        private void RestoreNative()
-        {
-            ScriptCharacterControllerData initData = new ScriptCharacterControllerData();
-            initData.position = SceneObject.Position;
-            initData.contactOffset = serializableData.contactOffset;
-            initData.stepOffset = serializableData.stepOffset;
-            initData.slopeLimit = serializableData.slopeLimit;
-            initData.minMoveDistance = serializableData.minMoveDistance;
-            initData.height = serializableData.height;
-            initData.radius = serializableData.radius;
-            initData.up = serializableData.up;
-            initData.climbingMode = serializableData.climbingMode;
-            initData.nonWalkableMode = serializableData.nonWalkableMode;
-
-            native = new NativeCharacterController(initData);
-            native.Component = this;
-            native.Layer = serializableData.layer;
-
-            UpdateDimensions();
-        }
-
-        /// <summary>
-        /// Destroys the internal character controller representation.
-        /// </summary>
-        private void DestroyNative()
-        {
-            if (native != null)
-            {
-                native.Destroy();
-                native = null;
-            }
-        }
-
-        /// <summary>
-        /// Holds all data the character controller component needs to persist through serialization.
-        /// </summary>
-        [SerializeObject]
-        internal class SerializableData
-        {
-            public float contactOffset = 0.1f;
-            public float stepOffset = 0.5f;
-            public Radian slopeLimit = new Degree(45.0f);
-            public float minMoveDistance = 0.0f;
-            public float height = 0.0f;
-            public float radius = 1.0f;
-            public Vector3 up = Vector3.YAxis;
-            public CharacterClimbingMode climbingMode = CharacterClimbingMode.Normal;
-            public CharacterNonWalkableMode nonWalkableMode = CharacterNonWalkableMode.Prevent;
-            public ulong layer = 1;
-        }
-    }
-
-    /// <summary>
-    /// Controls climbing behaviour for a capsule character controller. Normally the character controller will not
-    /// automatically climb when heights are greater than the assigned step offset.However due to the shape of the capsule
-    /// it might automatically climb over slightly larger heights than assigned step offsets.
-    /// </summary>
-    public enum CharacterClimbingMode
-    {
-        /// <summary>
-        /// Normal behaviour. Capsule character controller will be able to auto-step even above the step offset.
-        /// </summary>
-        Normal,
-        /// <summary>
-        /// The system will attempt to limit auto-step to the provided step offset and no higher.
-        /// </summary>
-		Constrained
-    }
-
-    /// <summary>
-    /// Controls behaviour when a character controller reaches a slope thats larger than its slope offset.
-    /// </summary>
-    public enum CharacterNonWalkableMode
-    {
-        /// <summary>
-        /// Character will be prevented from going further, but will be allowed to move laterally.
-        /// </summary>
-        Prevent,
-        /// <summary>
-        /// Character will be prevented from going further, but also slide down the slope.
-        /// </summary>
-		PreventAndSlide
-    }
-
-    /// <summary>
-    /// Reports in which directions is the character colliding with other objects.
-    /// </summary>
-    public enum CharacterCollisionFlag
-    {
-        /// <summary>
-        /// Character is colliding with its sides. 
-        /// </summary>
-        Sides = 0x1,
-        /// <summary>
-        /// Character is colliding with the ceiling.
-        /// </summary>
-		Up = 0x2,
-        /// <summary>
-        /// Character is colliding with the ground.
-        /// </summary>
-		Down = 0x4
-	}
-
-    /// <summary>
-    /// Used for passing CharacterController initialization data between native and managed code.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptCharacterControllerData // Note: Must match C++ struct CHAR_CONTROLLER_DESC
-    {
-        public Vector3 position;
-        public float contactOffset;
-        public float stepOffset;
-        public Radian slopeLimit;
-        public float minMoveDistance;
-        public float height;
-        public float radius;
-        public Vector3 up;
-        public CharacterClimbingMode climbingMode;
-        public CharacterNonWalkableMode nonWalkableMode;
-    }
-
-    /// <summary>
-    /// Used for passing ControllerCollision data between native and managed code.
-    /// </summary>
-    internal struct ScriptControllerCollision // Note: Must match C++ struct ScriptControllerCollision
-    {
-        public Vector3 position;
-        public Vector3 normal;
-        public Vector3 motionDir;
-        public float motionAmount;
-        public NativeCollider collider;
-        public int triangleIndex;
-        public NativeCharacterController controller;
-    }
-
-    /// <summary>
-    /// Contains data about a collision of a character controller and another object.
-    /// </summary>
-    public class ControllerCollision
-    {
-        /// <summary>
-        /// Contact position.
-        /// </summary>
-        public Vector3 position;
-
-        /// <summary>
-        /// Contact normal.
-        /// </summary>
-        public Vector3 normal;
-
-        /// <summary>
-        /// Direction of motion after the hit.
-        /// </summary>
-        public Vector3 motionDir;
-
-        /// <summary>
-        /// Magnitude of motion after the hit.
-        /// </summary>
-        public float motionAmount;
-    };
-
-    /// <summary>
-    /// Contains data about a collision of a character controller and a collider.
-    /// </summary>
-    public class ControllerColliderCollision : ControllerCollision
-    {
-        /// <summary>
-        /// Collider that was touched. 
-        /// </summary>
-        public Collider collider;
-
-        /// <summary>
-        /// Touched triangle index for mesh colliders.
-        /// </summary>
-        public int triangleIndex;
-    };
-
-    /// <summary>
-    /// Contains data about a collision between two character controllers.
-    /// </summary>
-    public class ControllerControllerCollision : ControllerCollision
-    {
-        /// <summary>
-        /// Controller that was touched.
-        /// </summary>
-        public CharacterController controller;
-    };
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Special physics controller meant to be used for game characters. Uses the "slide-and-collide" physics instead of
+    /// of the standard physics model to handle various issues with manually moving kinematic objects.Uses a capsule to
+    /// represent the character's bounds. 
+    /// </summary>
+    public sealed class CharacterController : Component
+    {
+        internal NativeCharacterController native;
+
+        [SerializeField]
+        internal SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Triggered when the controller hits a collider.
+        /// </summary>
+        public event Action<ControllerColliderCollision> OnColliderHit;
+
+        /// <summary>
+        /// Triggered when the controller hits another character controller.
+        /// </summary>
+        public event Action<ControllerControllerCollision> OnControllerHit;
+
+        /// <summary>
+        /// Position of the bottom of the controller. Position takes contact offset into account. Changing this value will 
+        /// teleport the character to the location. Use <see cref="Move"/> for movement that includes physics.
+        /// </summary>
+        public Vector3 FootPosition
+        {
+            get
+            {
+                if (native != null)
+                    return native.FootPosition;
+
+                return Vector3.Zero;
+            }
+            set
+            {
+                if (native != null)
+                {
+                    native.FootPosition = value;
+                    UpdatePositionFromController();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Radius of the controller capsule.
+        /// </summary>
+        public float Radius
+        {
+            get { return serializableData.radius; }
+            set
+            {
+                serializableData.radius = value;
+
+                if(native != null)
+                    UpdateDimensions();
+            }
+        }
+
+        /// <summary>
+        /// Height between the centers of the two spheres of the controller capsule.
+        /// </summary>
+        public float Height
+        {
+            get { return serializableData.height; }
+            set
+            {
+                serializableData.height = value;
+
+                if(native != null)
+                    UpdateDimensions();
+            }
+        }
+
+        /// <summary>
+        /// Up direction of capsule. Determines capsule orientation.
+        /// </summary>
+        public Vector3 Up
+        {
+            get { return serializableData.up; }
+            set
+            {
+                serializableData.up = value;
+
+                if (native != null)
+                    native.Up = value;
+            }
+        }
+
+        /// <summary>
+        /// Controls what happens when character encounters a height higher than its step offset. 
+        /// </summary>
+        public CharacterClimbingMode ClimbingMode
+        {
+            get { return serializableData.climbingMode; }
+            set
+            {
+                serializableData.climbingMode = value;
+
+                if (native != null)
+                    native.ClimbingMode = value;
+            }
+        }
+
+        /// <summary>
+        /// Controls what happens when character encounters a slope higher than its slope offset. 
+        /// </summary>
+        public CharacterNonWalkableMode NonWalkableMode
+        {
+            get { return serializableData.nonWalkableMode; }
+            set
+            {
+                serializableData.nonWalkableMode = value;
+
+                if (native != null)
+                    native.NonWalkableMode = value;
+            }
+        }
+
+        /// <summary>
+        /// Represents minimum distance that the character will move during a call to <see cref="Move"/>. This is used to
+        /// stop the recursive motion algorithm when the remaining distance is too small.
+        /// </summary>
+        public float MinMoveDistance
+        {
+            get { return serializableData.minMoveDistance; }
+            set
+            {
+                serializableData.minMoveDistance = value;
+
+                if (native != null)
+                    native.MinMoveDistance = value;
+            }
+        }
+
+        /// <summary>
+        /// Contact offset specifies a skin around the object within which contacts will be generated. It should be a small
+        /// positive non-zero value.
+        /// </summary>
+        public float ContactOffset
+        {
+            get { return serializableData.contactOffset; }
+            set
+            {
+                serializableData.contactOffset = value;
+
+                if (native != null)
+                    native.ContactOffset = value;
+            }
+        }
+
+        /// <summary>
+        /// Controls which obstacles will the character be able to automatically step over without being stopped. This is 
+        /// the height of the maximum obstacle that will be stepped over (with exceptions, <see cref="ClimbingMode"/>).
+        /// </summary>
+        public float StepOffset
+        {
+            get { return serializableData.stepOffset; }
+            set
+            {
+                serializableData.stepOffset = value;
+
+                if (native != null)
+                    native.StepOffset = value;
+            }
+        }
+
+        /// <summary>
+        /// Controls which slopes should the character consider too steep and won't be able to move over. 
+        /// <see cref="NonWalkableMode"/> for more information.
+        /// </summary>
+        public Radian SlopeLimit
+        {
+            get { return serializableData.slopeLimit; }
+            set
+            {
+                serializableData.slopeLimit = value;
+
+                if (native != null)
+                    native.SlopeLimit = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines what can the controller collide with. Objects that are allowed to collide with this object must have
+        /// the same bits set in their own layers.
+        /// </summary>
+        public ulong Layer
+        {
+            get { return serializableData.layer; }
+            set
+            {
+                serializableData.layer = value;
+
+                if (native != null)
+                    native.Layer = value;
+            }
+        }
+
+        /// <summary>
+        /// Moves the controller in the specified direction by the specified amount, while interacting with surrounding
+        /// geometry.Returns flags signaling where collision occurred after the movement.
+        /// 
+        /// Does not account for gravity, you must apply it manually.
+        /// </summary>
+        /// <param name="position">Position to move the controller to, in world space.</param>
+        public void Move(Vector3 position)
+        {
+            if (native == null)
+                return;
+
+            native.Move(position);
+            UpdatePositionFromController();
+        }
+
+        /// <summary>
+        /// Triggered when the controller hits a collider.
+        /// </summary>
+        /// <param name="data">Data about the collision.</param>
+        internal void DoOnColliderHit(ControllerColliderCollision data)
+        {
+            if (OnColliderHit != null)
+                OnColliderHit(data);
+        }
+
+        /// <summary>
+        /// Triggered when the controller hits another character controller.
+        /// </summary>
+        /// <param name="data">Data about the collision.</param>
+        internal void DoOnControllerHit(ControllerControllerCollision data)
+        {
+            if (OnControllerHit != null)
+                OnControllerHit(data);
+        }
+
+        private void OnInitialize()
+        {
+            NotifyFlags = TransformChangedFlags.Transform;
+        }
+
+        private void OnEnable()
+        {
+            RestoreNative();
+        }
+
+        private void OnDisable()
+        {
+            DestroyNative();
+        }
+
+        private void OnDestroy()
+        {
+            DestroyNative();
+        }
+
+        private void OnTransformChanged(TransformChangedFlags flags)
+        {
+            if (!SceneObject.Active || native == null)
+                return;
+
+            native.Position = SceneObject.Position;
+        }
+
+        /// <summary>
+        /// Updates the position by copying it from the controller to the component's scene object.
+        /// </summary>
+        private void UpdatePositionFromController()
+        {
+            NotifyFlags = 0;
+            SceneObject.Position = native.Position;
+            NotifyFlags = TransformChangedFlags.Transform;
+        }
+
+        /// <summary>
+        /// Updates the dimensions of the controller by taking account scale of the parent scene object.
+        /// </summary>
+        private void UpdateDimensions()
+        {
+            Vector3 scale = SceneObject.Scale;
+            float height = serializableData.height * MathEx.Abs(scale.y);
+            float radius = serializableData.radius * MathEx.Abs(MathEx.Max(scale.x, scale.z));
+
+            native.Height = height;
+            native.Radius = radius;
+        }
+
+        /// <summary>
+        /// Restores the internal character controller representation and initializes it with data stored by the component.
+        /// </summary>
+        private void RestoreNative()
+        {
+            ScriptCharacterControllerData initData = new ScriptCharacterControllerData();
+            initData.position = SceneObject.Position;
+            initData.contactOffset = serializableData.contactOffset;
+            initData.stepOffset = serializableData.stepOffset;
+            initData.slopeLimit = serializableData.slopeLimit;
+            initData.minMoveDistance = serializableData.minMoveDistance;
+            initData.height = serializableData.height;
+            initData.radius = serializableData.radius;
+            initData.up = serializableData.up;
+            initData.climbingMode = serializableData.climbingMode;
+            initData.nonWalkableMode = serializableData.nonWalkableMode;
+
+            native = new NativeCharacterController(initData);
+            native.Component = this;
+            native.Layer = serializableData.layer;
+
+            UpdateDimensions();
+        }
+
+        /// <summary>
+        /// Destroys the internal character controller representation.
+        /// </summary>
+        private void DestroyNative()
+        {
+            if (native != null)
+            {
+                native.Destroy();
+                native = null;
+            }
+        }
+
+        /// <summary>
+        /// Holds all data the character controller component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        internal class SerializableData
+        {
+            public float contactOffset = 0.1f;
+            public float stepOffset = 0.5f;
+            public Radian slopeLimit = new Degree(45.0f);
+            public float minMoveDistance = 0.0f;
+            public float height = 0.0f;
+            public float radius = 1.0f;
+            public Vector3 up = Vector3.YAxis;
+            public CharacterClimbingMode climbingMode = CharacterClimbingMode.Normal;
+            public CharacterNonWalkableMode nonWalkableMode = CharacterNonWalkableMode.Prevent;
+            public ulong layer = 1;
+        }
+    }
+
+    /// <summary>
+    /// Controls climbing behaviour for a capsule character controller. Normally the character controller will not
+    /// automatically climb when heights are greater than the assigned step offset.However due to the shape of the capsule
+    /// it might automatically climb over slightly larger heights than assigned step offsets.
+    /// </summary>
+    public enum CharacterClimbingMode
+    {
+        /// <summary>
+        /// Normal behaviour. Capsule character controller will be able to auto-step even above the step offset.
+        /// </summary>
+        Normal,
+        /// <summary>
+        /// The system will attempt to limit auto-step to the provided step offset and no higher.
+        /// </summary>
+		Constrained
+    }
+
+    /// <summary>
+    /// Controls behaviour when a character controller reaches a slope thats larger than its slope offset.
+    /// </summary>
+    public enum CharacterNonWalkableMode
+    {
+        /// <summary>
+        /// Character will be prevented from going further, but will be allowed to move laterally.
+        /// </summary>
+        Prevent,
+        /// <summary>
+        /// Character will be prevented from going further, but also slide down the slope.
+        /// </summary>
+		PreventAndSlide
+    }
+
+    /// <summary>
+    /// Reports in which directions is the character colliding with other objects.
+    /// </summary>
+    public enum CharacterCollisionFlag
+    {
+        /// <summary>
+        /// Character is colliding with its sides. 
+        /// </summary>
+        Sides = 0x1,
+        /// <summary>
+        /// Character is colliding with the ceiling.
+        /// </summary>
+		Up = 0x2,
+        /// <summary>
+        /// Character is colliding with the ground.
+        /// </summary>
+		Down = 0x4
+	}
+
+    /// <summary>
+    /// Used for passing CharacterController initialization data between native and managed code.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptCharacterControllerData // Note: Must match C++ struct CHAR_CONTROLLER_DESC
+    {
+        public Vector3 position;
+        public float contactOffset;
+        public float stepOffset;
+        public Radian slopeLimit;
+        public float minMoveDistance;
+        public float height;
+        public float radius;
+        public Vector3 up;
+        public CharacterClimbingMode climbingMode;
+        public CharacterNonWalkableMode nonWalkableMode;
+    }
+
+    /// <summary>
+    /// Used for passing ControllerCollision data between native and managed code.
+    /// </summary>
+    internal struct ScriptControllerCollision // Note: Must match C++ struct ScriptControllerCollision
+    {
+        public Vector3 position;
+        public Vector3 normal;
+        public Vector3 motionDir;
+        public float motionAmount;
+        public NativeCollider collider;
+        public int triangleIndex;
+        public NativeCharacterController controller;
+    }
+
+    /// <summary>
+    /// Contains data about a collision of a character controller and another object.
+    /// </summary>
+    public class ControllerCollision
+    {
+        /// <summary>
+        /// Contact position.
+        /// </summary>
+        public Vector3 position;
+
+        /// <summary>
+        /// Contact normal.
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// Direction of motion after the hit.
+        /// </summary>
+        public Vector3 motionDir;
+
+        /// <summary>
+        /// Magnitude of motion after the hit.
+        /// </summary>
+        public float motionAmount;
+    };
+
+    /// <summary>
+    /// Contains data about a collision of a character controller and a collider.
+    /// </summary>
+    public class ControllerColliderCollision : ControllerCollision
+    {
+        /// <summary>
+        /// Collider that was touched. 
+        /// </summary>
+        public Collider collider;
+
+        /// <summary>
+        /// Touched triangle index for mesh colliders.
+        /// </summary>
+        public int triangleIndex;
+    };
+
+    /// <summary>
+    /// Contains data about a collision between two character controllers.
+    /// </summary>
+    public class ControllerControllerCollision : ControllerCollision
+    {
+        /// <summary>
+        /// Controller that was touched.
+        /// </summary>
+        public CharacterController controller;
+    };
 }

+ 3 - 9
Source/MBansheeEngine/Physics/Collider.cs

@@ -224,7 +224,7 @@ namespace BansheeEngine
         /// <param name="isInternal">If true the rigidbody will just be changed internally, but parent rigidbody will not be
         ///                          notified.</param>
         internal void SetRigidbody(Rigidbody rigidbody, bool isInternal = false)
-	    {
+        {
 		    if (rigidbody == parent)
 			    return;
 
@@ -238,7 +238,7 @@ namespace BansheeEngine
 			    if (rigidbody != null)
                     nativeRigidbody = rigidbody.native;
 
-		        native.Rigidbody = nativeRigidbody;;
+		        native.Rigidbody = nativeRigidbody;
 
 			    if (rigidbody != null)
 				    rigidbody.AddCollider(this);
@@ -388,15 +388,9 @@ namespace BansheeEngine
             NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
         }
 
-        private void OnReset()
-        {
-            RestoreNative();
-        }
-
         private void OnEnable()
         {
-            if (native == null)
-                RestoreNative();
+            RestoreNative();
         }
 
         private void OnDisable()

+ 1397 - 1403
Source/MBansheeEngine/Physics/Joint.cs

@@ -1,1404 +1,1398 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (e.g. a door 
-    /// hinge). One of the bodies in the joint must always be movable (i.e. non-kinematic).
-    /// </summary>
-    public abstract class Joint : Component
-    {
-        internal NativeJoint native;
-
-        [SerializeField]
-        internal SerializableData serializableData = new SerializableData();
-
-        /// <summary>
-        /// Triggered when the joint's break force or torque is exceeded.
-        /// </summary>
-        public event Action OnJointBreak;
-
-        /// <summary>
-        /// Maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation.
-        /// </summary>
-        public float BreakForce
-        {
-            get { return serializableData.breakForce; }
-            set
-            {
-                if (serializableData.breakForce == value)
-                    return;
-
-                serializableData.breakForce = value;
-
-                if (native != null)
-                    native.BreakForce = value;
-            }
-        }
-
-        /// <summary>
-        /// Sets the maximum force the joint can apply before breaking. Broken joints no longer participate in physics
-        /// simulation.
-        /// </summary>
-        public float BreakTorque
-        {
-            get { return serializableData.breakTorque; }
-            set
-            {
-                if (serializableData.breakTorque == value)
-                    return;
-
-                serializableData.breakTorque = value;
-
-                if (native != null)
-                    native.BreakTorque = value;
-            }
-        }
-
-        /// <summary>
-        /// Determines whether collisions between the two bodies managed by the joint are enabled.
-        /// </summary>
-        public bool EnableCollision
-        {
-            get { return serializableData.enableCollision; }
-            set
-            {
-                if (serializableData.enableCollision == value)
-                    return;
-
-                serializableData.enableCollision = value;
-
-                if (native != null)
-                    native.EnableCollision = value;
-            }
-        }
-
-        /// <summary>
-        /// Returns one of the bodies managed by the joint.
-        /// </summary>
-        /// <param name="body">Which of the rigidbodies to return.</param>
-        /// <returns>Rigidbody managed by the joint, or null if none.</returns>
-        public Rigidbody GetRigidbody(JointBody body)
-        {
-            return serializableData.bodies[(int) body];
-        }
-
-        /// <summary>
-        /// Sets a body managed by the joint. One of the bodies must be movable (i.e. non-kinematic).
-        /// </summary>
-        /// <param name="body">Which of the rigidbodies to set.</param>
-        /// <param name="rigidbody">Rigidbody to managed by the joint, or null. If one of the bodies is null the other
-        ///                         one will be anchored globally to the position/rotation set by <see cref="SetPosition"/>
-        ///                         and <see cref="SetRotation"/>.</param>
-        public void SetRigidbody(JointBody body, Rigidbody rigidbody)
-        {
-            if (serializableData.bodies[(int)body] == rigidbody)
-                return;
-
-            if (serializableData.bodies[(int)body] != null)
-                serializableData.bodies[(int)body].SetJoint(null);
-
-            serializableData.bodies[(int)body] = rigidbody;
-
-            if (rigidbody != null)
-                serializableData.bodies[(int)body].SetJoint(this);
-
-            if (native != null)
-            {
-                native.SetRigidbody(body, rigidbody);
-                UpdateTransform(body);
-            }
-        }
-
-        /// <summary>
-        /// Returns the position at which the body is anchored to the joint.
-        /// </summary>
-        /// <param name="body">Which body to retrieve position for.</param>
-        /// <returns>Position relative to the body.</returns>
-        public Vector3 GetPosition(JointBody body)
-        {
-            return serializableData.positions[(int)body];
-        }
-
-        /// <summary>
-        /// Sets the position at which the body is anchored to the joint.
-        /// </summary>
-        /// <param name="body">Which body set the position for.</param>
-        /// <param name="position">Position relative to the body.</param>
-        public void SetPosition(JointBody body, Vector3 position)
-        {
-            if (serializableData.positions[(int)body] == position)
-                return;
-
-            serializableData.positions[(int) body] = position;
-
-            if (native != null)
-                UpdateTransform(body);
-        }
-
-        /// <summary>
-        /// Returns the rotation at which the body is anchored to the joint.
-        /// </summary>
-        /// <param name="body">Which body to retrieve rotation for.</param>
-        /// <returns>Rotation relative to the body.</returns>
-        public Quaternion GetRotation(JointBody body)
-        {
-            return serializableData.rotations[(int)body];
-        }
-
-        /// <summary>
-        /// Sets the rotation at which the body is anchored to the joint.
-        /// </summary>
-        /// <param name="body">Which body set the rotation for.</param>
-        /// <param name="rotation">Rotation relative to the body.</param>
-        public void SetRotation(JointBody body, Quaternion rotation)
-        {
-            if (serializableData.rotations[(int)body] == rotation)
-                return;
-
-            serializableData.rotations[(int)body] = rotation;
-
-            if (native != null)
-                UpdateTransform(body);
-        }
-
-        /// <summary>
-        /// Triggered when the joint breaks.
-        /// </summary>
-        internal void DoOnJointBreak()
-        {
-            if (OnJointBreak != null)
-                OnJointBreak();
-        }
-
-        /// <summary>
-        /// Notifies the joint that one of the attached rigidbodies moved and that its transform needs updating.
-        /// </summary>
-        /// <param name="body">Rigidbody that moved.</param>
-	    internal void NotifyRigidbodyMoved(Rigidbody body)
-	    {
-		    // If physics update is in progress do nothing, as its the joint itself that's probably moving the body
-		    if (Physics.IsUpdateInProgress)
-			    return;
-
-		    if (serializableData.bodies[0] == body)
-			    UpdateTransform(JointBody.A);
-		    else if (serializableData.bodies[1] == body)
-			    UpdateTransform(JointBody.B);
-	    }
-
-        /// <summary>
-        /// Creates the internal representation of the Joint for use by the component.
-        /// </summary>
-        /// <returns>New native joint object.</returns>
-        internal abstract NativeJoint CreateNative();
-
-        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()
-        {
-            if (serializableData.bodies[0] != null)
-                serializableData.bodies[0].SetJoint(null);
-
-            if (serializableData.bodies[1] != null)
-                serializableData.bodies[1].SetJoint(null);
-
-            DestroyNative();
-        }
-
-        private void OnTransformChanged(TransformChangedFlags flags)
-        {
-            if (!SceneObject.Active)
-                return;
-
-            // We're ignoring this during physics update because it would cause problems if the joint itself was moved by physics
-            // Note: This isn't particularily correct because if the joint is being moved by physics but the rigidbodies
-            // themselves are not parented to the joint, the transform will need updating. However I'm leaving it up to the
-            // user to ensure rigidbodies are always parented to the joint in such a case (It's an unlikely situation that
-            // I can't think of an use for - joint transform will almost always be set as an initialization step and not a 
-            // physics response).
-            if (Physics.IsUpdateInProgress)
-                return;
-
-            UpdateTransform(JointBody.A);
-            UpdateTransform(JointBody.B);
-        }
-
-        /// <summary>
-        /// Creates the internal representation of the Joint and restores the values saved by the Component.
-        /// </summary>
-        private void RestoreNative()
-	    {
-            native = CreateNative();
-
-            // Note: Merge into one call to avoid many virtual function calls
-            Rigidbody[] bodies = new Rigidbody[2];
-
-		    if (serializableData.bodies[0] != null)
-			    bodies[0] = serializableData.bodies[0];
-		    else
-			    bodies[0] = null;
-
-		    if (serializableData.bodies[1] != null)
-			    bodies[1] = serializableData.bodies[1];
-		    else
-			    bodies[1] = null;
-
-		    native.SetRigidbody(JointBody.A, bodies[0]);
-		    native.SetRigidbody(JointBody.B, bodies[1]);
-		    native.BreakForce = serializableData.breakForce;
-            native.BreakTorque = serializableData.breakTorque;
-            native.EnableCollision = serializableData.enableCollision;
-		    native.BreakTorque = serializableData.breakTorque;
-            native.EnableCollision = serializableData.enableCollision;
-
-		    UpdateTransform(JointBody.A);
-		    UpdateTransform(JointBody.B);
-	    }
-
-        /// <summary>
-        /// Destroys the internal joint representation.
-        /// </summary>
-        private void DestroyNative()
-	    {
-	        if (native != null)
-	        {
-	            native.Destroy();
-                native = null;
-	        }
-	    }
-
-        /// <summary>
-        /// Updates the local transform for the specified body attached to the joint.
-        /// </summary>
-        /// <param name="body">Body to update.</param>
-	    private void UpdateTransform(JointBody body)
-	    {
-		    Vector3 localPos;
-		    Quaternion localRot;
-
-		    localPos = serializableData.positions[(int)body];
-		    localRot = serializableData.rotations[(int)body];
-
-		    // Transform to world space of the related body
-		    Rigidbody rigidbody = serializableData.bodies[(int)body];
-		    if (rigidbody != null)
-		    {
-			    localRot = rigidbody.SceneObject.Rotation * localRot;
-			    localPos = localRot.Rotate(localPos) + rigidbody.SceneObject.Position;
-		    }
-
-		    // Transform to space local to the joint
-		    Quaternion invRotation = SceneObject.Rotation.Inverse;
-
-		    localPos = invRotation.Rotate(localPos - SceneObject.Position);
-		    localRot = invRotation * localRot;
-
-		    native.SetPosition(body, localPos);
-            native.SetRotation(body, localRot);
-	    }
-
-        /// <summary>
-        /// Holds all data the joint component needs to persist through serialization.
-        /// </summary>
-        [SerializeObject]
-        internal class SerializableData
-        {
-            public Rigidbody[] bodies = new Rigidbody[2];
-            public Vector3[] positions = new Vector3[2];
-            public Quaternion[] rotations = new Quaternion[2];
-            public float breakForce = float.MaxValue;
-            public float breakTorque = float.MaxValue;
-            public bool enableCollision = false;
-        }
-    }
-
-    /// <summary>
-    /// Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restitution when 
-    /// the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential), SerializeObject]
-    public struct Spring // Note: Must match C++ struct Spring
-    {
-        /// <summary>
-        /// Constructs a spring.
-        /// </summary>
-        /// <param name="stiffness">Spring strength.Force proportional to the position error.</param>
-        /// <param name="damping">Damping strength. Force propertional to the velocity error.</param>
-        public Spring(float stiffness, float damping)
-        {
-            this.stiffness = stiffness;
-            this.damping = damping;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is Spring)
-            {
-                Spring other = (Spring)rhs;
-                return stiffness == other.stiffness && damping == other.damping;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(Spring a, Spring b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(Spring a, Spring b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Spring strength. Force proportional to the position error.
-        /// </summary>
-        public float stiffness;
-
-        /// <summary>
-        /// Damping strength. Force propertional to the velocity error.
-        /// </summary>
-        public float damping;
-	}
-
-    /// <summary>
-    /// Specifies first or second body referenced by a Joint.
-    /// </summary>
-    public enum JointBody
-    {
-        A, B
-    };
-
-    /// <summary>
-    /// Specifies axes that the D6 joint can constrain motion on.
-    /// </summary>
-    public enum D6JointAxis
-    {
-        /// <summary>
-        /// Movement on the X axis. 
-        /// </summary>
-        X,
-        /// <summary>
-        /// Movement on the Y axis.
-        /// </summary>
-		Y,
-        /// <summary>
-        /// Movement on the Z axis.
-        /// </summary>
-		Z,
-        /// <summary>
-        /// Rotation around the X axis.
-        /// </summary>
-		Twist,
-        /// <summary>
-        /// Rotation around the Y axis.
-        /// </summary>
-        SwingY,
-        /// <summary>
-        /// Rotation around the Z axis.
-        /// </summary>
-        SwingZ,
-		Count
-    }
-
-    /// <summary>
-    /// Specifies type of constraint placed on a specific axis of a D6 joint.
-    /// </summary>
-    public enum D6JointMotion
-    {
-        /// <summary>
-        /// Axis is immovable.
-        /// </summary>
-        Locked,
-        /// <summary>
-        /// Axis will be constrained by the specified limits.
-        /// </summary>
-        Limited,
-        /// <summary>
-        /// Axis will not be constrained.
-        /// </summary>
-        Free,
-		Count
-    }
-
-    /// <summary>
-    /// Type of drives that can be used for moving or rotating bodies attached to the D6 joint.
-    /// </summary>
-    public enum D6JointDriveType
-    {
-        /// <summary>
-        /// Linear movement on the X axis using the linear drive model.
-        /// </summary>
-        X,
-        /// <summary>
-        /// Linear movement on the Y axis using the linear drive model.
-        /// </summary>
-        Y,
-        /// <summary>
-        /// Linear movement on the Z axis using the linear drive model.
-        /// </summary>
-        Z,
-        /// <summary>
-        /// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with 
-        /// SLERP mode. 
-        /// </summary>
-		Swing, 
-        /// <summary>
-        /// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with 
-        /// SLERP mode.
-        /// </summary>
-		Twist,
-        /// <summary>
-        /// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
-        /// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
-        /// they all must be unlocked).
-        /// </summary>
-		SLERP, 
-		Count
-    }
-
-    /// <summary>
-    /// Specifies parameters for a drive that will attempt to move the D6 joint bodies to the specified drive position and
-    /// velocity.
-    /// </summary>
-    [SerializeObject]
-    public class D6JointDrive
-    {
-        [SerializeField]
-        private D6JointDriveData data;
-
-        /// <summary>
-        /// Spring strength. Force proportional to the position error.
-        /// </summary>
-        public float Stiffness { get { return data.stiffness; } }
-
-        /// <summary>
-        /// Damping strength. Force propertional to the velocity error.
-        /// </summary>
-        public float Damping { get { return data.damping; } }
-
-        /// <summary>
-        /// Maximum force the drive can apply.
-        /// </summary>
-        public float ForceLimit { get { return data.forceLimit; } }
-
-        /// <summary>
-        /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
-        /// they account for the masses of the actors to which the joint is attached.
-        /// </summary>
-        public bool Acceleration { get { return data.acceleration; } }
-
-        /// <summary>
-        /// Gets drive properties.
-        /// </summary>
-        public D6JointDriveData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs a new D6 joint drive.
-        /// </summary>
-        /// <param name="stiffness"><see cref="Stiffness"/></param>
-        /// <param name="damping"><see cref="Damping"/></param>
-        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
-        /// <param name="acceleration"><see cref="Acceleration"/></param>
-        public D6JointDrive(float stiffness = 0.0f, float damping = 0.0f, float forceLimit = float.MaxValue,
-            bool acceleration = false)
-        {
-            data.stiffness = stiffness;
-            data.damping = damping;
-            data.forceLimit = forceLimit;
-            data.acceleration = acceleration;
-        }
-
-        /// <summary>
-        /// Constructs a new D6 joint drive.
-        /// </summary>
-        /// <param name="data">Properties to initialize the drive with.</param>
-        public D6JointDrive(D6JointDriveData data)
-        {
-            this.data = data;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is D6JointDrive)
-            {
-                D6JointDrive other = (D6JointDrive)rhs;
-                return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit 
-                    && Acceleration == other.Acceleration;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(D6JointDrive a, D6JointDrive b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(D6JointDrive a, D6JointDrive b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing drive data from native code.
-        /// </summary>
-        /// <param name="output">Native readable drive structure.</param>
-        private void Internal_GetNative(out D6JointDriveData output)
-        {
-            output = data;
-        }
-    }
-
-    /// <summary>
-    /// Properties of a drive that drives the hinge joint's angular velocity towards a paricular value.
-    /// </summary>
-    [SerializeObject]
-    public class HingeJointDrive
-    {
-        [SerializeField]
-        private HingeJointDriveData data;
-
-        /// <summary>
-        /// Target speed of the joint.
-        /// </summary>
-        public float Speed { get { return data.speed; } }
-
-        /// <summary>
-        /// Maximum torque the drive is allowed to apply.
-        /// </summary>
-        public float ForceLimit { get { return data.forceLimit; } }
-
-        /// <summary>
-        /// Scales the velocity of the first body, and its response to drive torque is scaled down.
-        /// </summary>
-        public float GearRatio { get { return data.gearRatio; } }
-
-        /// <summary>
-        /// If the joint is moving faster than the drive's target speed, the drive will try to break. If you don't want
-        /// the breaking to happen set this to true.
-        /// </summary>
-        public bool FreeSpin { get { return data.freeSpin; } }
-
-        /// <summary>
-        /// Gets drive properties.
-        /// </summary>
-        public HingeJointDriveData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs a new hinge joint drive.
-        /// </summary>
-        /// <param name="speed"><see cref="Speed"/></param>
-        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
-        /// <param name="gearRatio"><see cref="GearRatio"/></param>
-        /// <param name="freeSpin"><see cref="FreeSpin"/></param>
-        public HingeJointDrive(float speed = 0.0f, float forceLimit = float.MaxValue, 
-            float gearRatio = 1.0f, bool freeSpin = false)
-        {
-            data.speed = speed;
-            data.forceLimit = forceLimit;
-            data.gearRatio = gearRatio;
-            data.freeSpin = freeSpin;
-        }
-
-        /// <summary>
-        /// Constructs a new hinge joint drive.
-        /// </summary>
-        /// <param name="data">Properties to initialize the drive with.</param>
-        public HingeJointDrive(HingeJointDriveData data)
-        {
-            this.data = data;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is HingeJointDrive)
-            {
-                HingeJointDrive other = (HingeJointDrive)rhs;
-                return data.speed == other.data.speed && data.gearRatio == other.data.gearRatio && 
-                    data.forceLimit == other.data.forceLimit && data.freeSpin == other.data.freeSpin;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(HingeJointDrive a, HingeJointDrive b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(HingeJointDrive a, HingeJointDrive b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing drive data from native code.
-        /// </summary>
-        /// <param name="output">Native readable drive structure.</param>
-        private void Internal_GetNative(out HingeJointDriveData output)
-        {
-            output = data;
-        }
-    };
-
-    /// <summary>
-    /// Contains common values used by all Joint limit types.
-    /// </summary>
-    [SerializeObject]
-    public class LimitCommon
-    {
-        private LimitCommonData data;
-
-        /// <summary>
-        /// Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
-        /// reached to avoid breaking the limit.
-        /// </summary>
-        public float ContactDist { get { return data.contactDist; } }
-
-        /// <summary>
-        /// Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
-        /// while those closer to one specify more ellastic(i.e bouncy) collision.Must be in [0, 1] range.
-        /// </summary>
-		public float Restitution { get { return data.restitution; } }
-
-        /// <summary>
-        /// Spring that controls how are the bodies pulled back towards the limit when they breach it.
-        /// </summary>
-        public Spring Spring { get { return data.spring; } }
-
-        /// <summary>
-        /// Gets properties common to all limit types.
-        /// </summary>
-        public LimitCommonData CommonData
-        {
-            get { return data; }
-        }
-
-        protected LimitCommon(float contactDist = -1.0f)
-        {
-            data.contactDist = contactDist;
-            data.restitution = 0.0f;
-            data.spring = new Spring();
-        }
-
-        protected LimitCommon(Spring spring, float restitution = 0.0f)
-        {
-            data.contactDist = -1.0f;
-            data.restitution = restitution;
-            data.spring = spring;
-        }
-
-        protected LimitCommon(LimitCommonData data)
-        {
-            this.data = data;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is LimitCommon)
-            {
-                LimitCommon other = (LimitCommon)rhs;
-                return ContactDist == other.ContactDist && Restitution == other.Restitution && Spring == other.Spring;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(LimitCommon a, LimitCommon b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(LimitCommon a, LimitCommon b)
-        {
-            return !(a == b);
-        }
-    }
-
-    /// <summary>
-    /// Represents a joint limit between two distance values. Lower value must be less than the upper value.
-    /// </summary>
-    [SerializeObject]
-    public class LimitLinearRange : LimitCommon
-    {
-        private LimitLinearRangeData data;
-
-        /// <summary>
-        /// Lower distance of the limit. Must be less than <see cref="Upper"/>.
-        /// </summary>
-        public float Lower { get { return data.lower; } }
-
-        /// <summary>
-        /// Upper distance of the limit. Must be greater than <see cref="Lower"/>.
-        /// </summary>
-        public float Upper { get { return data.upper; } }
-
-        /// <summary>
-        /// Gets properties of the linear limit range.
-        /// </summary>
-        public LimitLinearRangeData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs an empty limit.
-        /// </summary>
-        public LimitLinearRange()
-        { }
-
-        /// <summary>
-        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
-        /// </summary>
-        /// <param name="lower"><see cref="Lower"/></param>
-        /// <param name="upper"><see cref="Upper"/></param>
-        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
-        public LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
-            :base(contactDist)
-        {
-            data.lower = lower;
-            data.upper = upper;
-        }
-
-        /// <summary>
-        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
-        /// parameter and will be pulled back towards the limit by the provided spring.
-        /// </summary>
-        /// <param name="lower"><see cref="Lower"/></param>
-        /// <param name="upper"><see cref="Upper"/></param>
-        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
-        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
-        public LimitLinearRange(float lower, float upper, Spring spring, float restitution = 0.0f)
-            :base(spring, restitution)
-        {
-            data.lower = lower;
-            data.upper = upper;
-        }
-
-        /// <summary>
-        /// Constructs a new limit from the provided properties.
-        /// </summary>
-        /// <param name="limitData">Linear range specific properties.</param>
-        /// <param name="commonData">Properties common to all limit types.</param>
-        public LimitLinearRange(LimitLinearRangeData limitData, LimitCommonData commonData)
-            :base(commonData)
-        {
-            this.data = limitData;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is LimitLinearRange)
-            {
-                LimitLinearRange other = (LimitLinearRange)rhs;
-                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(LimitLinearRange a, LimitLinearRange b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(LimitLinearRange a, LimitLinearRange b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing limit data from native code.
-        /// </summary>
-        /// <param name="output">Native readable limit structure.</param>
-        private void Internal_GetNative(ref ScriptLimitLinearRange output)
-        {
-            output.contactDist = ContactDist;
-            output.restitution = Restitution;
-            output.spring = Spring;
-            output.lower = Lower;
-            output.upper = Upper;
-        }
-    }
-
-    /// <summary>
-    /// Represents a joint limit between zero a single distance value.
-    /// </summary>
-    [SerializeObject]
-    public class LimitLinear : LimitCommon
-    {
-        private LimitLinearData data;
-
-        /// <summary>
-        /// Distance at which the limit becomes active.
-        /// </summary>
-        public float Extent { get { return data.extent; } }
-
-        /// <summary>
-        /// Gets properties of the linear limit.
-        /// </summary>
-        public LimitLinearData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs an empty limit.
-        /// </summary>
-        public LimitLinear()
-		{ }
-
-        /// <summary>
-        /// Constructs a hard limit.Once the limit is reached the movement of the attached bodies will come to a stop.
-        /// </summary>
-        /// <param name="extent"><see cref="Extent"/></param>
-        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
-        public LimitLinear(float extent, float contactDist = -1.0f)
-			:base(contactDist)
-        {
-            data.extent = extent;
-        }
-
-        /// <summary>
-        /// Constructs a soft limit.Once the limit is reached the bodies will bounce back according to the resitution
-        /// parameter and will be pulled back towards the limit by the provided spring.
-        /// </summary>
-        /// <param name="extent"><see cref="Extent"/></param>
-        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
-        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
-		public LimitLinear(float extent, Spring spring, float restitution = 0.0f)
-			:base(spring, restitution)
-        {
-            data.extent = extent;
-        }
-
-        /// <summary>
-        /// Constructs a new limit from the provided properties.
-        /// </summary>
-        /// <param name="limitData">Linear limit specific properties.</param>
-        /// <param name="commonData">Properties common to all limit types.</param>
-        public LimitLinear(LimitLinearData limitData, LimitCommonData commonData)
-            :base(commonData)
-        {
-            this.data = limitData;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is LimitLinear)
-            {
-                LimitLinear other = (LimitLinear)rhs;
-                return base.Equals(rhs) && Extent == other.Extent;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(LimitLinear a, LimitLinear b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(LimitLinear a, LimitLinear b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing limit data from native code.
-        /// </summary>
-        /// <param name="output">Native readable limit structure.</param>
-        private void Internal_GetNative(ref ScriptLimitLinear output)
-        {
-            output.contactDist = ContactDist;
-            output.restitution = Restitution;
-            output.spring = Spring;
-            output.extent = Extent;
-        }
-    }
-
-    /// <summary>
-    /// Represents a joint limit between two angles.
-    /// </summary>
-    [SerializeObject]
-    public class LimitAngularRange : LimitCommon
-	{
-        private LimitAngularRangeData data;
-
-        /// <summary>
-        /// Lower angle of the limit. Must be less than <see cref="Upper"/>.
-        /// </summary>
-        public Radian Lower { get { return data.lower; } }
-
-        /// <summary>
-        /// Upper angle of the limit. Must be greater than <see cref="Lower"/>.
-        /// </summary>
-        public Radian Upper { get { return data.upper; } }
-
-        /// <summary>
-        /// Gets properties of the angular limit range.
-        /// </summary>
-        public LimitAngularRangeData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs an empty limit.
-        /// </summary>
-        public LimitAngularRange()
-		{ }
-
-        /// <summary>
-        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
-        /// </summary>
-        /// <param name="lower"><see cref="Lower"/></param>
-        /// <param name="upper"><see cref="Upper"/></param>
-        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
-        public LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
-            : base(contactDist)
-        {
-            data.lower = lower;
-            data.upper = upper;
-        }
-
-        /// <summary>
-        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
-        /// parameter and will be pulled back towards the limit by the provided spring.
-        /// </summary>
-        /// <param name="lower"><see cref="Lower"/></param>
-        /// <param name="upper"><see cref="Upper"/></param>
-        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
-        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
-        public LimitAngularRange(Radian lower, Radian upper, Spring spring, float restitution = 0.0f)
-            : base(spring, restitution)
-        {
-            data.lower = lower;
-            data.upper = upper;
-        }
-
-        /// <summary>
-        /// Constructs a new limit from the provided properties.
-        /// </summary>
-        /// <param name="limitData">Angular limit range specific properties.</param>
-        /// <param name="commonData">Properties common to all limit types.</param>
-        public LimitAngularRange(LimitAngularRangeData limitData, LimitCommonData commonData)
-            :base(commonData)
-        {
-            this.data = limitData;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is LimitAngularRange)
-            {
-                LimitAngularRange other = (LimitAngularRange)rhs;
-                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(LimitAngularRange a, LimitAngularRange b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(LimitAngularRange a, LimitAngularRange b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing limit data from native code.
-        /// </summary>
-        /// <param name="output">Native readable limit structure.</param>
-        private void Internal_GetNative(ref ScriptLimitAngularRange output)
-        {
-            output.contactDist = ContactDist;
-            output.restitution = Restitution;
-            output.spring = Spring;
-            output.lower = Lower;
-            output.upper = Upper;
-        }
-    }
-
-    /// <summary>
-    /// Represents a joint limit that contraints movement to within an elliptical cone.
-    /// </summary>
-    [SerializeObject]
-    public class LimitConeRange : LimitCommon
-    {
-        private LimitConeRangeData data;
-
-        /// <summary>
-        /// Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
-        /// </summary>
-        public Radian YLimitAngle { get { return data.yLimitAngle; } }
-
-        /// <summary>
-        /// Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
-        /// </summary>
-        public Radian ZLimitAngle { get { return data.zLimitAngle; } }
-
-        /// <summary>
-        /// Gets properties of the cone limit range.
-        /// </summary>
-        public LimitConeRangeData Data
-        {
-            get { return data; }
-        }
-
-        /// <summary>
-        /// Constructs a limit with a 45 degree cone.
-        /// </summary>
-        public LimitConeRange()
-        {
-            data.yLimitAngle = new Radian(MathEx.Pi * 0.5f);
-            data.zLimitAngle = new Radian(MathEx.Pi * 0.5f);
-        }
-
-        /// <summary>
-        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
-        /// </summary>
-        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
-        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
-        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
-        public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
-            : base(contactDist)
-        {
-            data.yLimitAngle = yLimitAngle;
-            data.zLimitAngle = zLimitAngle;
-        }
-
-        /// <summary>
-        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
-        /// parameter and will be pulled back towards the limit by the provided spring.
-        /// </summary>
-        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
-        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
-        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
-        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
-        public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, Spring spring, float restitution = 0.0f)
-            : base(spring, restitution)
-        {
-            data.yLimitAngle = yLimitAngle;
-            data.zLimitAngle = zLimitAngle;
-        }
-
-        /// <summary>
-        /// Constructs a new limit from the provided properties.
-        /// </summary>
-        /// <param name="limitData">Cone limit range specific properties.</param>
-        /// <param name="commonData">Properties common to all limit types.</param>
-        public LimitConeRange(LimitConeRangeData limitData, LimitCommonData commonData)
-            :base(commonData)
-        {
-            this.data = limitData;
-        }
-
-        /// <inheritdoc/>
-        public override bool Equals(object rhs)
-        {
-            if (rhs is LimitConeRange)
-            {
-                LimitConeRange other = (LimitConeRange)rhs;
-                return base.Equals(rhs) && YLimitAngle == other.YLimitAngle && ZLimitAngle == other.ZLimitAngle;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public static bool operator ==(LimitConeRange a, LimitConeRange b)
-        {
-            return a.Equals(b);
-        }
-
-        public static bool operator !=(LimitConeRange a, LimitConeRange b)
-        {
-            return !(a == b);
-        }
-
-        /// <summary>
-        /// Used for accessing limit data from native code.
-        /// </summary>
-        /// <param name="output">Native readable limit structure.</param>
-        private void Internal_GetNative(ref ScriptLimitConeRange output)
-        {
-            output.contactDist = ContactDist;
-            output.restitution = Restitution;
-            output.spring = Spring;
-            output.yLimitAngle = YLimitAngle;
-            output.zLimitAngle = ZLimitAngle;
-        }
-	}
-
-    /// <summary>
-    /// Contains data used by HingeJointDrive.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct HingeJointDriveData // Note: Must match C++ struct HingeJoint::Drive
-    {
-        /// <summary>
-        /// <see cref="HingeJointDrive.Speed"/>
-        /// </summary>
-        public float speed;
-
-        /// <summary>
-        /// <see cref="HingeJointDrive.ForceLimit"/>
-        /// </summary>
-        public float forceLimit;
-
-        /// <summary>
-        /// <see cref="HingeJointDrive.GearRatio"/>
-        /// </summary>
-        public float gearRatio;
-
-        /// <summary>
-        /// <see cref="HingeJointDrive.FreeSpin"/>
-        /// </summary>
-        public bool freeSpin;
-    }
-
-    /// <summary>
-    /// Contains data used by D6JointDrive.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct D6JointDriveData // Note: Must match C++ struct D6Joint::Drive
-    {
-        /// <summary>
-        /// <see cref="D6JointDrive.Stiffness"/>
-        /// </summary>
-        public float stiffness;
-
-        /// <summary>
-        /// <see cref="D6JointDrive.Damping"/>
-        /// </summary>
-        public float damping;
-
-        /// <summary>
-        /// <see cref="D6JointDrive.ForceLimit"/>
-        /// </summary>
-        public float forceLimit;
-
-        /// <summary>
-        /// <see cref="D6JointDrive.Acceleration"/>
-        /// </summary>
-        public bool acceleration;
-    }
-
-    /// <summary>
-    /// Contains data used by LimitCommon.
-    /// </summary>
-    public struct LimitCommonData
-    {
-        /// <summary>
-        /// <see cref="LimitCommon.ContactDist"/>
-        /// </summary>
-        public float contactDist;
-
-        /// <summary>
-        /// <see cref="LimitCommon.Restitution"/>
-        /// </summary>
-        public float restitution;
-
-        /// <summary>
-        /// <see cref="LimitCommon.Spring"/>
-        /// </summary>
-        public Spring spring;
-    }
-
-    /// <summary>
-    /// Contains data used by LimitLinearRange.
-    /// </summary>
-    public struct LimitLinearRangeData
-    {
-        /// <summary>
-        /// <see cref="LimitLinearRange.Lower"/>
-        /// </summary>
-        public float lower;
-        /// <summary>
-        /// <see cref="LimitLinearRange.Upper"/>
-        /// </summary>
-        public float upper;
-    }
-
-    /// <summary>
-    /// Contains data used by LimitLinear.
-    /// </summary>
-    public struct LimitLinearData
-    {
-        /// <summary>
-        /// <see cref="LimitLinearRange.Extent"/>
-        /// </summary>
-        public float extent;
-    }
-
-    /// <summary>
-    /// Contains data used by LimitAngularRange.
-    /// </summary>
-    public struct LimitAngularRangeData
-    {
-        /// <summary>
-        /// <see cref="LimitAngularRange.Lower"/>
-        /// </summary>
-        public Radian lower;
-        /// <summary>
-        /// <see cref="LimitAngularRange.Upper"/>
-        /// </summary>
-        public Radian upper;
-    }
-
-    /// <summary>
-    /// Contains data used by LimitConeRange.
-    /// </summary>
-    public struct LimitConeRangeData
-    {
-        /// <summary>
-        /// <see cref="LimitConeRange.YLimitAngle"/>
-        /// </summary>
-        public Radian yLimitAngle;
-        /// <summary>
-        /// <see cref="LimitConeRange.ZLimitAngle"/>
-        /// </summary>
-        public Radian zLimitAngle;
-    }
-
-    /// <summary>
-    /// Used for passing LimitLinearRange data between native and managed code.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptLimitLinearRange // Note: Must match C++ struct LimitLinearRange
-    {
-        public float contactDist;
-        public float restitution;
-        public Spring spring;
-        public float lower;
-        public float upper;
-    }
-
-    /// <summary>
-    /// Used for passing LimitLinear data between native and managed code.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptLimitLinear // Note: Must match C++ struct LimitLinear
-    {
-        public float contactDist;
-        public float restitution;
-        public Spring spring;
-        public float extent;
-    }
-
-    /// <summary>
-    /// Used for passing LimitAngularRange data between native and managed code.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptLimitAngularRange // Note: Must match C++ struct LimitAngularRange
-    {
-        public float contactDist;
-        public float restitution;
-        public Spring spring;
-        public Radian lower;
-        public Radian upper;
-    }
-
-    /// <summary>
-    /// Used for passing LimitConeRange data between native and managed code.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptLimitConeRange // Note: Must match C++ struct LimitConeRange
-    {
-        public float contactDist;
-        public float restitution;
-        public Spring spring;
-        public Radian yLimitAngle;
-        public Radian zLimitAngle;
-    }
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (e.g. a door 
+    /// hinge). One of the bodies in the joint must always be movable (i.e. non-kinematic).
+    /// </summary>
+    public abstract class Joint : Component
+    {
+        internal NativeJoint native;
+
+        [SerializeField]
+        internal SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Triggered when the joint's break force or torque is exceeded.
+        /// </summary>
+        public event Action OnJointBreak;
+
+        /// <summary>
+        /// Maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation.
+        /// </summary>
+        public float BreakForce
+        {
+            get { return serializableData.breakForce; }
+            set
+            {
+                if (serializableData.breakForce == value)
+                    return;
+
+                serializableData.breakForce = value;
+
+                if (native != null)
+                    native.BreakForce = value;
+            }
+        }
+
+        /// <summary>
+        /// Sets the maximum force the joint can apply before breaking. Broken joints no longer participate in physics
+        /// simulation.
+        /// </summary>
+        public float BreakTorque
+        {
+            get { return serializableData.breakTorque; }
+            set
+            {
+                if (serializableData.breakTorque == value)
+                    return;
+
+                serializableData.breakTorque = value;
+
+                if (native != null)
+                    native.BreakTorque = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether collisions between the two bodies managed by the joint are enabled.
+        /// </summary>
+        public bool EnableCollision
+        {
+            get { return serializableData.enableCollision; }
+            set
+            {
+                if (serializableData.enableCollision == value)
+                    return;
+
+                serializableData.enableCollision = value;
+
+                if (native != null)
+                    native.EnableCollision = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns one of the bodies managed by the joint.
+        /// </summary>
+        /// <param name="body">Which of the rigidbodies to return.</param>
+        /// <returns>Rigidbody managed by the joint, or null if none.</returns>
+        public Rigidbody GetRigidbody(JointBody body)
+        {
+            return serializableData.bodies[(int) body];
+        }
+
+        /// <summary>
+        /// Sets a body managed by the joint. One of the bodies must be movable (i.e. non-kinematic).
+        /// </summary>
+        /// <param name="body">Which of the rigidbodies to set.</param>
+        /// <param name="rigidbody">Rigidbody to managed by the joint, or null. If one of the bodies is null the other
+        ///                         one will be anchored globally to the position/rotation set by <see cref="SetPosition"/>
+        ///                         and <see cref="SetRotation"/>.</param>
+        public void SetRigidbody(JointBody body, Rigidbody rigidbody)
+        {
+            if (serializableData.bodies[(int)body] == rigidbody)
+                return;
+
+            if (serializableData.bodies[(int)body] != null)
+                serializableData.bodies[(int)body].SetJoint(null);
+
+            serializableData.bodies[(int)body] = rigidbody;
+
+            if (rigidbody != null)
+                serializableData.bodies[(int)body].SetJoint(this);
+
+            if (native != null)
+            {
+                native.SetRigidbody(body, rigidbody);
+                UpdateTransform(body);
+            }
+        }
+
+        /// <summary>
+        /// Returns the position at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body to retrieve position for.</param>
+        /// <returns>Position relative to the body.</returns>
+        public Vector3 GetPosition(JointBody body)
+        {
+            return serializableData.positions[(int)body];
+        }
+
+        /// <summary>
+        /// Sets the position at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body set the position for.</param>
+        /// <param name="position">Position relative to the body.</param>
+        public void SetPosition(JointBody body, Vector3 position)
+        {
+            if (serializableData.positions[(int)body] == position)
+                return;
+
+            serializableData.positions[(int) body] = position;
+
+            if (native != null)
+                UpdateTransform(body);
+        }
+
+        /// <summary>
+        /// Returns the rotation at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body to retrieve rotation for.</param>
+        /// <returns>Rotation relative to the body.</returns>
+        public Quaternion GetRotation(JointBody body)
+        {
+            return serializableData.rotations[(int)body];
+        }
+
+        /// <summary>
+        /// Sets the rotation at which the body is anchored to the joint.
+        /// </summary>
+        /// <param name="body">Which body set the rotation for.</param>
+        /// <param name="rotation">Rotation relative to the body.</param>
+        public void SetRotation(JointBody body, Quaternion rotation)
+        {
+            if (serializableData.rotations[(int)body] == rotation)
+                return;
+
+            serializableData.rotations[(int)body] = rotation;
+
+            if (native != null)
+                UpdateTransform(body);
+        }
+
+        /// <summary>
+        /// Triggered when the joint breaks.
+        /// </summary>
+        internal void DoOnJointBreak()
+        {
+            if (OnJointBreak != null)
+                OnJointBreak();
+        }
+
+        /// <summary>
+        /// Notifies the joint that one of the attached rigidbodies moved and that its transform needs updating.
+        /// </summary>
+        /// <param name="body">Rigidbody that moved.</param>
+	    internal void NotifyRigidbodyMoved(Rigidbody body)
+	    {
+		    // If physics update is in progress do nothing, as its the joint itself that's probably moving the body
+		    if (Physics.IsUpdateInProgress)
+			    return;
+
+		    if (serializableData.bodies[0] == body)
+			    UpdateTransform(JointBody.A);
+		    else if (serializableData.bodies[1] == body)
+			    UpdateTransform(JointBody.B);
+	    }
+
+        /// <summary>
+        /// Creates the internal representation of the Joint for use by the component.
+        /// </summary>
+        /// <returns>New native joint object.</returns>
+        internal abstract NativeJoint CreateNative();
+
+        private void OnInitialize()
+        {
+            NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
+        }
+
+        private void OnEnable()
+        {
+            RestoreNative();
+        }
+
+        private void OnDisable()
+        {
+            DestroyNative();
+        }
+
+        private void OnDestroy()
+        {
+            if (serializableData.bodies[0] != null)
+                serializableData.bodies[0].SetJoint(null);
+
+            if (serializableData.bodies[1] != null)
+                serializableData.bodies[1].SetJoint(null);
+
+            DestroyNative();
+        }
+
+        private void OnTransformChanged(TransformChangedFlags flags)
+        {
+            if (!SceneObject.Active)
+                return;
+
+            // We're ignoring this during physics update because it would cause problems if the joint itself was moved by physics
+            // Note: This isn't particularily correct because if the joint is being moved by physics but the rigidbodies
+            // themselves are not parented to the joint, the transform will need updating. However I'm leaving it up to the
+            // user to ensure rigidbodies are always parented to the joint in such a case (It's an unlikely situation that
+            // I can't think of an use for - joint transform will almost always be set as an initialization step and not a 
+            // physics response).
+            if (Physics.IsUpdateInProgress)
+                return;
+
+            UpdateTransform(JointBody.A);
+            UpdateTransform(JointBody.B);
+        }
+
+        /// <summary>
+        /// Creates the internal representation of the Joint and restores the values saved by the Component.
+        /// </summary>
+        private void RestoreNative()
+	    {
+            native = CreateNative();
+
+            // Note: Merge into one call to avoid many virtual function calls
+            Rigidbody[] bodies = new Rigidbody[2];
+
+		    if (serializableData.bodies[0] != null)
+			    bodies[0] = serializableData.bodies[0];
+		    else
+			    bodies[0] = null;
+
+		    if (serializableData.bodies[1] != null)
+			    bodies[1] = serializableData.bodies[1];
+		    else
+			    bodies[1] = null;
+
+		    native.SetRigidbody(JointBody.A, bodies[0]);
+		    native.SetRigidbody(JointBody.B, bodies[1]);
+		    native.BreakForce = serializableData.breakForce;
+            native.BreakTorque = serializableData.breakTorque;
+            native.EnableCollision = serializableData.enableCollision;
+		    native.BreakTorque = serializableData.breakTorque;
+            native.EnableCollision = serializableData.enableCollision;
+
+		    UpdateTransform(JointBody.A);
+		    UpdateTransform(JointBody.B);
+	    }
+
+        /// <summary>
+        /// Destroys the internal joint representation.
+        /// </summary>
+        private void DestroyNative()
+	    {
+	        if (native != null)
+	        {
+	            native.Destroy();
+                native = null;
+	        }
+	    }
+
+        /// <summary>
+        /// Updates the local transform for the specified body attached to the joint.
+        /// </summary>
+        /// <param name="body">Body to update.</param>
+	    private void UpdateTransform(JointBody body)
+	    {
+		    Vector3 localPos;
+		    Quaternion localRot;
+
+		    localPos = serializableData.positions[(int)body];
+		    localRot = serializableData.rotations[(int)body];
+
+		    // Transform to world space of the related body
+		    Rigidbody rigidbody = serializableData.bodies[(int)body];
+		    if (rigidbody != null)
+		    {
+			    localRot = rigidbody.SceneObject.Rotation * localRot;
+			    localPos = localRot.Rotate(localPos) + rigidbody.SceneObject.Position;
+		    }
+
+		    // Transform to space local to the joint
+		    Quaternion invRotation = SceneObject.Rotation.Inverse;
+
+		    localPos = invRotation.Rotate(localPos - SceneObject.Position);
+		    localRot = invRotation * localRot;
+
+		    native.SetPosition(body, localPos);
+            native.SetRotation(body, localRot);
+	    }
+
+        /// <summary>
+        /// Holds all data the joint component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        internal class SerializableData
+        {
+            public Rigidbody[] bodies = new Rigidbody[2];
+            public Vector3[] positions = new Vector3[2];
+            public Quaternion[] rotations = new Quaternion[2];
+            public float breakForce = float.MaxValue;
+            public float breakTorque = float.MaxValue;
+            public bool enableCollision = false;
+        }
+    }
+
+    /// <summary>
+    /// Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restitution when 
+    /// the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential), SerializeObject]
+    public struct Spring // Note: Must match C++ struct Spring
+    {
+        /// <summary>
+        /// Constructs a spring.
+        /// </summary>
+        /// <param name="stiffness">Spring strength.Force proportional to the position error.</param>
+        /// <param name="damping">Damping strength. Force propertional to the velocity error.</param>
+        public Spring(float stiffness, float damping)
+        {
+            this.stiffness = stiffness;
+            this.damping = damping;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is Spring)
+            {
+                Spring other = (Spring)rhs;
+                return stiffness == other.stiffness && damping == other.damping;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(Spring a, Spring b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(Spring a, Spring b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Spring strength. Force proportional to the position error.
+        /// </summary>
+        public float stiffness;
+
+        /// <summary>
+        /// Damping strength. Force propertional to the velocity error.
+        /// </summary>
+        public float damping;
+	}
+
+    /// <summary>
+    /// Specifies first or second body referenced by a Joint.
+    /// </summary>
+    public enum JointBody
+    {
+        A, B
+    };
+
+    /// <summary>
+    /// Specifies axes that the D6 joint can constrain motion on.
+    /// </summary>
+    public enum D6JointAxis
+    {
+        /// <summary>
+        /// Movement on the X axis. 
+        /// </summary>
+        X,
+        /// <summary>
+        /// Movement on the Y axis.
+        /// </summary>
+		Y,
+        /// <summary>
+        /// Movement on the Z axis.
+        /// </summary>
+		Z,
+        /// <summary>
+        /// Rotation around the X axis.
+        /// </summary>
+		Twist,
+        /// <summary>
+        /// Rotation around the Y axis.
+        /// </summary>
+        SwingY,
+        /// <summary>
+        /// Rotation around the Z axis.
+        /// </summary>
+        SwingZ,
+		Count
+    }
+
+    /// <summary>
+    /// Specifies type of constraint placed on a specific axis of a D6 joint.
+    /// </summary>
+    public enum D6JointMotion
+    {
+        /// <summary>
+        /// Axis is immovable.
+        /// </summary>
+        Locked,
+        /// <summary>
+        /// Axis will be constrained by the specified limits.
+        /// </summary>
+        Limited,
+        /// <summary>
+        /// Axis will not be constrained.
+        /// </summary>
+        Free,
+		Count
+    }
+
+    /// <summary>
+    /// Type of drives that can be used for moving or rotating bodies attached to the D6 joint.
+    /// </summary>
+    public enum D6JointDriveType
+    {
+        /// <summary>
+        /// Linear movement on the X axis using the linear drive model.
+        /// </summary>
+        X,
+        /// <summary>
+        /// Linear movement on the Y axis using the linear drive model.
+        /// </summary>
+        Y,
+        /// <summary>
+        /// Linear movement on the Z axis using the linear drive model.
+        /// </summary>
+        Z,
+        /// <summary>
+        /// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with 
+        /// SLERP mode. 
+        /// </summary>
+		Swing, 
+        /// <summary>
+        /// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with 
+        /// SLERP mode.
+        /// </summary>
+		Twist,
+        /// <summary>
+        /// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
+        /// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
+        /// they all must be unlocked).
+        /// </summary>
+		SLERP, 
+		Count
+    }
+
+    /// <summary>
+    /// Specifies parameters for a drive that will attempt to move the D6 joint bodies to the specified drive position and
+    /// velocity.
+    /// </summary>
+    [SerializeObject]
+    public class D6JointDrive
+    {
+        [SerializeField]
+        private D6JointDriveData data;
+
+        /// <summary>
+        /// Spring strength. Force proportional to the position error.
+        /// </summary>
+        public float Stiffness { get { return data.stiffness; } }
+
+        /// <summary>
+        /// Damping strength. Force propertional to the velocity error.
+        /// </summary>
+        public float Damping { get { return data.damping; } }
+
+        /// <summary>
+        /// Maximum force the drive can apply.
+        /// </summary>
+        public float ForceLimit { get { return data.forceLimit; } }
+
+        /// <summary>
+        /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
+        /// they account for the masses of the actors to which the joint is attached.
+        /// </summary>
+        public bool Acceleration { get { return data.acceleration; } }
+
+        /// <summary>
+        /// Gets drive properties.
+        /// </summary>
+        public D6JointDriveData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs a new D6 joint drive.
+        /// </summary>
+        /// <param name="stiffness"><see cref="Stiffness"/></param>
+        /// <param name="damping"><see cref="Damping"/></param>
+        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
+        /// <param name="acceleration"><see cref="Acceleration"/></param>
+        public D6JointDrive(float stiffness = 0.0f, float damping = 0.0f, float forceLimit = float.MaxValue,
+            bool acceleration = false)
+        {
+            data.stiffness = stiffness;
+            data.damping = damping;
+            data.forceLimit = forceLimit;
+            data.acceleration = acceleration;
+        }
+
+        /// <summary>
+        /// Constructs a new D6 joint drive.
+        /// </summary>
+        /// <param name="data">Properties to initialize the drive with.</param>
+        public D6JointDrive(D6JointDriveData data)
+        {
+            this.data = data;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is D6JointDrive)
+            {
+                D6JointDrive other = (D6JointDrive)rhs;
+                return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit 
+                    && Acceleration == other.Acceleration;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(D6JointDrive a, D6JointDrive b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(D6JointDrive a, D6JointDrive b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing drive data from native code.
+        /// </summary>
+        /// <param name="output">Native readable drive structure.</param>
+        private void Internal_GetNative(out D6JointDriveData output)
+        {
+            output = data;
+        }
+    }
+
+    /// <summary>
+    /// Properties of a drive that drives the hinge joint's angular velocity towards a paricular value.
+    /// </summary>
+    [SerializeObject]
+    public class HingeJointDrive
+    {
+        [SerializeField]
+        private HingeJointDriveData data;
+
+        /// <summary>
+        /// Target speed of the joint.
+        /// </summary>
+        public float Speed { get { return data.speed; } }
+
+        /// <summary>
+        /// Maximum torque the drive is allowed to apply.
+        /// </summary>
+        public float ForceLimit { get { return data.forceLimit; } }
+
+        /// <summary>
+        /// Scales the velocity of the first body, and its response to drive torque is scaled down.
+        /// </summary>
+        public float GearRatio { get { return data.gearRatio; } }
+
+        /// <summary>
+        /// If the joint is moving faster than the drive's target speed, the drive will try to break. If you don't want
+        /// the breaking to happen set this to true.
+        /// </summary>
+        public bool FreeSpin { get { return data.freeSpin; } }
+
+        /// <summary>
+        /// Gets drive properties.
+        /// </summary>
+        public HingeJointDriveData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs a new hinge joint drive.
+        /// </summary>
+        /// <param name="speed"><see cref="Speed"/></param>
+        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
+        /// <param name="gearRatio"><see cref="GearRatio"/></param>
+        /// <param name="freeSpin"><see cref="FreeSpin"/></param>
+        public HingeJointDrive(float speed = 0.0f, float forceLimit = float.MaxValue, 
+            float gearRatio = 1.0f, bool freeSpin = false)
+        {
+            data.speed = speed;
+            data.forceLimit = forceLimit;
+            data.gearRatio = gearRatio;
+            data.freeSpin = freeSpin;
+        }
+
+        /// <summary>
+        /// Constructs a new hinge joint drive.
+        /// </summary>
+        /// <param name="data">Properties to initialize the drive with.</param>
+        public HingeJointDrive(HingeJointDriveData data)
+        {
+            this.data = data;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is HingeJointDrive)
+            {
+                HingeJointDrive other = (HingeJointDrive)rhs;
+                return data.speed == other.data.speed && data.gearRatio == other.data.gearRatio && 
+                    data.forceLimit == other.data.forceLimit && data.freeSpin == other.data.freeSpin;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(HingeJointDrive a, HingeJointDrive b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(HingeJointDrive a, HingeJointDrive b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing drive data from native code.
+        /// </summary>
+        /// <param name="output">Native readable drive structure.</param>
+        private void Internal_GetNative(out HingeJointDriveData output)
+        {
+            output = data;
+        }
+    };
+
+    /// <summary>
+    /// Contains common values used by all Joint limit types.
+    /// </summary>
+    [SerializeObject]
+    public class LimitCommon
+    {
+        private LimitCommonData data;
+
+        /// <summary>
+        /// Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
+        /// reached to avoid breaking the limit.
+        /// </summary>
+        public float ContactDist { get { return data.contactDist; } }
+
+        /// <summary>
+        /// Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
+        /// while those closer to one specify more ellastic(i.e bouncy) collision.Must be in [0, 1] range.
+        /// </summary>
+		public float Restitution { get { return data.restitution; } }
+
+        /// <summary>
+        /// Spring that controls how are the bodies pulled back towards the limit when they breach it.
+        /// </summary>
+        public Spring Spring { get { return data.spring; } }
+
+        /// <summary>
+        /// Gets properties common to all limit types.
+        /// </summary>
+        public LimitCommonData CommonData
+        {
+            get { return data; }
+        }
+
+        protected LimitCommon(float contactDist = -1.0f)
+        {
+            data.contactDist = contactDist;
+            data.restitution = 0.0f;
+            data.spring = new Spring();
+        }
+
+        protected LimitCommon(Spring spring, float restitution = 0.0f)
+        {
+            data.contactDist = -1.0f;
+            data.restitution = restitution;
+            data.spring = spring;
+        }
+
+        protected LimitCommon(LimitCommonData data)
+        {
+            this.data = data;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is LimitCommon)
+            {
+                LimitCommon other = (LimitCommon)rhs;
+                return ContactDist == other.ContactDist && Restitution == other.Restitution && Spring == other.Spring;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LimitCommon a, LimitCommon b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(LimitCommon a, LimitCommon b)
+        {
+            return !(a == b);
+        }
+    }
+
+    /// <summary>
+    /// Represents a joint limit between two distance values. Lower value must be less than the upper value.
+    /// </summary>
+    [SerializeObject]
+    public class LimitLinearRange : LimitCommon
+    {
+        private LimitLinearRangeData data;
+
+        /// <summary>
+        /// Lower distance of the limit. Must be less than <see cref="Upper"/>.
+        /// </summary>
+        public float Lower { get { return data.lower; } }
+
+        /// <summary>
+        /// Upper distance of the limit. Must be greater than <see cref="Lower"/>.
+        /// </summary>
+        public float Upper { get { return data.upper; } }
+
+        /// <summary>
+        /// Gets properties of the linear limit range.
+        /// </summary>
+        public LimitLinearRangeData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs an empty limit.
+        /// </summary>
+        public LimitLinearRange()
+        { }
+
+        /// <summary>
+        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
+        /// </summary>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
+        public LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
+            :base(contactDist)
+        {
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
+        /// parameter and will be pulled back towards the limit by the provided spring.
+        /// </summary>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
+        public LimitLinearRange(float lower, float upper, Spring spring, float restitution = 0.0f)
+            :base(spring, restitution)
+        {
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Linear range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitLinearRange(LimitLinearRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is LimitLinearRange)
+            {
+                LimitLinearRange other = (LimitLinearRange)rhs;
+                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LimitLinearRange a, LimitLinearRange b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(LimitLinearRange a, LimitLinearRange b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing limit data from native code.
+        /// </summary>
+        /// <param name="output">Native readable limit structure.</param>
+        private void Internal_GetNative(ref ScriptLimitLinearRange output)
+        {
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.lower = Lower;
+            output.upper = Upper;
+        }
+    }
+
+    /// <summary>
+    /// Represents a joint limit between zero a single distance value.
+    /// </summary>
+    [SerializeObject]
+    public class LimitLinear : LimitCommon
+    {
+        private LimitLinearData data;
+
+        /// <summary>
+        /// Distance at which the limit becomes active.
+        /// </summary>
+        public float Extent { get { return data.extent; } }
+
+        /// <summary>
+        /// Gets properties of the linear limit.
+        /// </summary>
+        public LimitLinearData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs an empty limit.
+        /// </summary>
+        public LimitLinear()
+		{ }
+
+        /// <summary>
+        /// Constructs a hard limit.Once the limit is reached the movement of the attached bodies will come to a stop.
+        /// </summary>
+        /// <param name="extent"><see cref="Extent"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
+        public LimitLinear(float extent, float contactDist = -1.0f)
+			:base(contactDist)
+        {
+            data.extent = extent;
+        }
+
+        /// <summary>
+        /// Constructs a soft limit.Once the limit is reached the bodies will bounce back according to the resitution
+        /// parameter and will be pulled back towards the limit by the provided spring.
+        /// </summary>
+        /// <param name="extent"><see cref="Extent"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
+		public LimitLinear(float extent, Spring spring, float restitution = 0.0f)
+			:base(spring, restitution)
+        {
+            data.extent = extent;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Linear limit specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitLinear(LimitLinearData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is LimitLinear)
+            {
+                LimitLinear other = (LimitLinear)rhs;
+                return base.Equals(rhs) && Extent == other.Extent;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LimitLinear a, LimitLinear b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(LimitLinear a, LimitLinear b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing limit data from native code.
+        /// </summary>
+        /// <param name="output">Native readable limit structure.</param>
+        private void Internal_GetNative(ref ScriptLimitLinear output)
+        {
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.extent = Extent;
+        }
+    }
+
+    /// <summary>
+    /// Represents a joint limit between two angles.
+    /// </summary>
+    [SerializeObject]
+    public class LimitAngularRange : LimitCommon
+	{
+        private LimitAngularRangeData data;
+
+        /// <summary>
+        /// Lower angle of the limit. Must be less than <see cref="Upper"/>.
+        /// </summary>
+        public Radian Lower { get { return data.lower; } }
+
+        /// <summary>
+        /// Upper angle of the limit. Must be greater than <see cref="Lower"/>.
+        /// </summary>
+        public Radian Upper { get { return data.upper; } }
+
+        /// <summary>
+        /// Gets properties of the angular limit range.
+        /// </summary>
+        public LimitAngularRangeData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs an empty limit.
+        /// </summary>
+        public LimitAngularRange()
+		{ }
+
+        /// <summary>
+        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
+        /// </summary>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
+        public LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
+            : base(contactDist)
+        {
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
+        /// parameter and will be pulled back towards the limit by the provided spring.
+        /// </summary>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
+        public LimitAngularRange(Radian lower, Radian upper, Spring spring, float restitution = 0.0f)
+            : base(spring, restitution)
+        {
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Angular limit range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitAngularRange(LimitAngularRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is LimitAngularRange)
+            {
+                LimitAngularRange other = (LimitAngularRange)rhs;
+                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LimitAngularRange a, LimitAngularRange b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(LimitAngularRange a, LimitAngularRange b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing limit data from native code.
+        /// </summary>
+        /// <param name="output">Native readable limit structure.</param>
+        private void Internal_GetNative(ref ScriptLimitAngularRange output)
+        {
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.lower = Lower;
+            output.upper = Upper;
+        }
+    }
+
+    /// <summary>
+    /// Represents a joint limit that contraints movement to within an elliptical cone.
+    /// </summary>
+    [SerializeObject]
+    public class LimitConeRange : LimitCommon
+    {
+        private LimitConeRangeData data;
+
+        /// <summary>
+        /// Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
+        /// </summary>
+        public Radian YLimitAngle { get { return data.yLimitAngle; } }
+
+        /// <summary>
+        /// Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
+        /// </summary>
+        public Radian ZLimitAngle { get { return data.zLimitAngle; } }
+
+        /// <summary>
+        /// Gets properties of the cone limit range.
+        /// </summary>
+        public LimitConeRangeData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs a limit with a 45 degree cone.
+        /// </summary>
+        public LimitConeRange()
+        {
+            data.yLimitAngle = new Radian(MathEx.Pi * 0.5f);
+            data.zLimitAngle = new Radian(MathEx.Pi * 0.5f);
+        }
+
+        /// <summary>
+        /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
+        /// </summary>
+        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
+        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
+        public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
+            : base(contactDist)
+        {
+            data.yLimitAngle = yLimitAngle;
+            data.zLimitAngle = zLimitAngle;
+        }
+
+        /// <summary>
+        /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
+        /// parameter and will be pulled back towards the limit by the provided spring.
+        /// </summary>
+        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
+        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
+        public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, Spring spring, float restitution = 0.0f)
+            : base(spring, restitution)
+        {
+            data.yLimitAngle = yLimitAngle;
+            data.zLimitAngle = zLimitAngle;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Cone limit range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitConeRange(LimitConeRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object rhs)
+        {
+            if (rhs is LimitConeRange)
+            {
+                LimitConeRange other = (LimitConeRange)rhs;
+                return base.Equals(rhs) && YLimitAngle == other.YLimitAngle && ZLimitAngle == other.ZLimitAngle;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public static bool operator ==(LimitConeRange a, LimitConeRange b)
+        {
+            return a.Equals(b);
+        }
+
+        public static bool operator !=(LimitConeRange a, LimitConeRange b)
+        {
+            return !(a == b);
+        }
+
+        /// <summary>
+        /// Used for accessing limit data from native code.
+        /// </summary>
+        /// <param name="output">Native readable limit structure.</param>
+        private void Internal_GetNative(ref ScriptLimitConeRange output)
+        {
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.yLimitAngle = YLimitAngle;
+            output.zLimitAngle = ZLimitAngle;
+        }
+	}
+
+    /// <summary>
+    /// Contains data used by HingeJointDrive.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct HingeJointDriveData // Note: Must match C++ struct HingeJoint::Drive
+    {
+        /// <summary>
+        /// <see cref="HingeJointDrive.Speed"/>
+        /// </summary>
+        public float speed;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.ForceLimit"/>
+        /// </summary>
+        public float forceLimit;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.GearRatio"/>
+        /// </summary>
+        public float gearRatio;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.FreeSpin"/>
+        /// </summary>
+        public bool freeSpin;
+    }
+
+    /// <summary>
+    /// Contains data used by D6JointDrive.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct D6JointDriveData // Note: Must match C++ struct D6Joint::Drive
+    {
+        /// <summary>
+        /// <see cref="D6JointDrive.Stiffness"/>
+        /// </summary>
+        public float stiffness;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.Damping"/>
+        /// </summary>
+        public float damping;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.ForceLimit"/>
+        /// </summary>
+        public float forceLimit;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.Acceleration"/>
+        /// </summary>
+        public bool acceleration;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitCommon.
+    /// </summary>
+    public struct LimitCommonData
+    {
+        /// <summary>
+        /// <see cref="LimitCommon.ContactDist"/>
+        /// </summary>
+        public float contactDist;
+
+        /// <summary>
+        /// <see cref="LimitCommon.Restitution"/>
+        /// </summary>
+        public float restitution;
+
+        /// <summary>
+        /// <see cref="LimitCommon.Spring"/>
+        /// </summary>
+        public Spring spring;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitLinearRange.
+    /// </summary>
+    public struct LimitLinearRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitLinearRange.Lower"/>
+        /// </summary>
+        public float lower;
+        /// <summary>
+        /// <see cref="LimitLinearRange.Upper"/>
+        /// </summary>
+        public float upper;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitLinear.
+    /// </summary>
+    public struct LimitLinearData
+    {
+        /// <summary>
+        /// <see cref="LimitLinearRange.Extent"/>
+        /// </summary>
+        public float extent;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitAngularRange.
+    /// </summary>
+    public struct LimitAngularRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitAngularRange.Lower"/>
+        /// </summary>
+        public Radian lower;
+        /// <summary>
+        /// <see cref="LimitAngularRange.Upper"/>
+        /// </summary>
+        public Radian upper;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitConeRange.
+    /// </summary>
+    public struct LimitConeRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitConeRange.YLimitAngle"/>
+        /// </summary>
+        public Radian yLimitAngle;
+        /// <summary>
+        /// <see cref="LimitConeRange.ZLimitAngle"/>
+        /// </summary>
+        public Radian zLimitAngle;
+    }
+
+    /// <summary>
+    /// Used for passing LimitLinearRange data between native and managed code.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptLimitLinearRange // Note: Must match C++ struct LimitLinearRange
+    {
+        public float contactDist;
+        public float restitution;
+        public Spring spring;
+        public float lower;
+        public float upper;
+    }
+
+    /// <summary>
+    /// Used for passing LimitLinear data between native and managed code.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptLimitLinear // Note: Must match C++ struct LimitLinear
+    {
+        public float contactDist;
+        public float restitution;
+        public Spring spring;
+        public float extent;
+    }
+
+    /// <summary>
+    /// Used for passing LimitAngularRange data between native and managed code.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptLimitAngularRange // Note: Must match C++ struct LimitAngularRange
+    {
+        public float contactDist;
+        public float restitution;
+        public Spring spring;
+        public Radian lower;
+        public Radian upper;
+    }
+
+    /// <summary>
+    /// Used for passing LimitConeRange data between native and managed code.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptLimitConeRange // Note: Must match C++ struct LimitConeRange
+    {
+        public float contactDist;
+        public float restitution;
+        public Spring spring;
+        public Radian yLimitAngle;
+        public Radian zLimitAngle;
+    }
 }

+ 396 - 396
Source/MBansheeEngine/Physics/NativeRigidbody.cs

@@ -1,396 +1,396 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native Rigidbody class.
-    /// <see cref="Rigidbody"/>
-    /// </summary>
-    internal class NativeRigidbody : ScriptObject
-    {
-        private Rigidbody component;
-
-        /// <summary>
-        /// Component that owns the native rigidbody object.
-        /// </summary>
-        public Rigidbody Component
-        {
-            get { return component; }
-            set { component = value; }
-        }
-
-        public Vector3 Position
-        {
-            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
-            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
-        }
-
-        public Quaternion Rotation
-        {
-            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
-            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
-        }
-
-        public float Mass
-        {
-            get { return Internal_GetMass(mCachedPtr); }
-            set { Internal_SetMass(mCachedPtr, value); }
-        }
-
-        public bool Kinematic
-        {
-            get { return Internal_GetIsKinematic(mCachedPtr); }
-            set { Internal_SetIsKinematic(mCachedPtr, value); }
-        }
-
-        public bool Sleeping
-        {
-            get { return Internal_IsSleeping(mCachedPtr); }
-            set
-            {
-                if (value)
-                    Internal_Sleep(mCachedPtr);
-                else
-                    Internal_WakeUp(mCachedPtr);
-            }
-        }
-
-        public float SleepThreshold
-        {
-            get { return Internal_GetSleepThreshold(mCachedPtr); }
-            set { Internal_SetSleepThreshold(mCachedPtr, value); }
-        }
-
-        public bool UseGravity
-        {
-            get { return Internal_GetUseGravity(mCachedPtr); }
-            set { Internal_SetUseGravity(mCachedPtr, value); }
-        }
-
-        public Vector3 Velocity
-        {
-            get { Vector3 velocity; Internal_GetVelocity(mCachedPtr, out velocity); return velocity; }
-            set { Internal_SetVelocity(mCachedPtr, ref value); }
-        }
-
-        public Vector3 AngularVelocity
-        {
-            get { Vector3 velocity; Internal_GetAngularVelocity(mCachedPtr, out velocity); return velocity; }
-            set { Internal_SetAngularVelocity(mCachedPtr, ref value); }
-        }
-
-        public float Drag
-        {
-            get { return Internal_GetDrag(mCachedPtr); }
-            set { Internal_SetDrag(mCachedPtr, value); }
-        }
-
-        public float AngularDrag
-        {
-            get { return Internal_GetAngularDrag(mCachedPtr); }
-            set { Internal_SetAngularDrag(mCachedPtr, value); }
-        }
-
-        public Vector3 InertiaTensor
-        {
-            get { Vector3 tensor; Internal_GetInertiaTensor(mCachedPtr, out tensor); return tensor; }
-            set { Internal_SetInertiaTensor(mCachedPtr, ref value); }
-        }
-
-        public Vector3 CenterOfMassPosition
-        {
-            get { Vector3 pos; Internal_GetCenterOfMassPosition(mCachedPtr, out pos); return pos; }
-            set { Quaternion rot = CenterOfMassRotation; Internal_SetCenterOfMass(mCachedPtr, ref value, ref rot); }
-        }
-
-        public Quaternion CenterOfMassRotation
-        {
-            get { Quaternion rot; Internal_GetCenterOfMassRotation(mCachedPtr, out rot); return rot; }
-            set { Vector3 pos = CenterOfMassPosition; Internal_SetCenterOfMass(mCachedPtr, ref pos, ref value); }
-        }
-
-        public float MaxAngularVelocity
-        {
-            get { return Internal_GetMaxAngularVelocity(mCachedPtr); }
-            set { Internal_SetMaxAngularVelocity(mCachedPtr, value); }
-        }
-
-        public int PositionSolverCount
-        {
-            get { return Internal_GetPositionSolverCount(mCachedPtr); }
-            set { Internal_SetPositionSolverCount(mCachedPtr, value); }
-        }
-
-        public int VelocitySolverCount
-        {
-            get { return Internal_GetVelocitySolverCount(mCachedPtr); }
-            set { Internal_SetVelocitySolverCount(mCachedPtr, value); }
-        }
-
-        public RigidbodyInterpolationMode InterpolationMode
-        {
-            get { return Internal_GetInterpolationMode(mCachedPtr); }
-            set { Internal_SetInterpolationMode(mCachedPtr, value); }
-        }
-
-        public RigidbodyFlag Flags
-        {
-            get { return Internal_GetFlags(mCachedPtr); }
-            set { Internal_SetFlags(mCachedPtr, value); }
-        }
-
-        public NativeRigidbody(SceneObject linkedSO)
-        {
-            IntPtr linkedSOPtr = IntPtr.Zero;
-            if (linkedSO != null)
-                linkedSOPtr = linkedSO.GetCachedPtr();
-
-            Internal_CreateInstance(this, linkedSOPtr);
-        }
-
-        public void Destroy()
-        {
-            Internal_Destroy(mCachedPtr);
-        }
-
-        public void Move(Vector3 position)
-        {
-            Internal_Move(mCachedPtr, ref position);
-        }
-
-        public void Rotate(Quaternion rotation)
-        {
-            Internal_Rotate(mCachedPtr, ref rotation);
-        }
-
-        public void AddForce(Vector3 force, ForceMode mode)
-        {
-            Internal_AddForce(mCachedPtr, ref force, mode);
-        }
-
-        public void AddTorque(Vector3 torque, ForceMode mode)
-        {
-            Internal_AddTorque(mCachedPtr, ref torque, mode);
-        }
-
-        public void AddForceAtPoint(Vector3 force, Vector3 position, PointForceMode mode)
-        {
-            Internal_AddForceAtPoint(mCachedPtr, ref force, ref position, mode);
-        }
-
-        public Vector3 GetVelocityAtPoint(Vector3 position)
-        {
-            Vector3 velocity;
-            Internal_GetVelocityAtPoint(mCachedPtr, ref position, out velocity);
-            return velocity;
-        }
-
-        public void AddCollider(Collider collider)
-        {
-            if (collider == null)
-                return;
-
-            IntPtr colliderPtr = collider.GetCachedPtr();
-            Internal_AddCollider(mCachedPtr, colliderPtr);
-        }
-
-        public void RemoveCollider(Collider collider)
-        {
-            if (collider == null)
-                return;
-
-            IntPtr colliderPtr = collider.GetCachedPtr();
-            Internal_RemoveCollider(mCachedPtr, colliderPtr);
-        }
-
-        public void RemoveColliders()
-        {
-            Internal_RemoveColliders(mCachedPtr);
-        }
-
-        public void UpdateMassDistribution()
-        {
-            Internal_UpdateMassDistribution(mCachedPtr);
-        }
-
-        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionBegin(collisionData);
-        }
-
-        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionStay(collisionData);
-        }
-
-        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionEnd(collisionData);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(NativeRigidbody instance, IntPtr linkedSO);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Rotate(IntPtr thisPtr, ref Quaternion rotation);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rotation);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetMass(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetIsKinematic(IntPtr thisPtr, bool kinematic);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetIsKinematic(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_IsSleeping(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Sleep(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_WakeUp(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetSleepThreshold(IntPtr thisPtr, float threshold);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetSleepThreshold(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetUseGravity(IntPtr thisPtr, bool gravity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetUseGravity(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetVelocity(IntPtr thisPtr, ref Vector3 velocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetVelocity(IntPtr thisPtr, out Vector3 velocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetAngularVelocity(IntPtr thisPtr, ref Vector3 velocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetAngularVelocity(IntPtr thisPtr, out Vector3 velocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetDrag(IntPtr thisPtr, float drag);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetDrag(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetAngularDrag(IntPtr thisPtr, float drag);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetAngularDrag(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetInertiaTensor(IntPtr thisPtr, ref Vector3 tensor);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetInertiaTensor(IntPtr thisPtr, out Vector3 tensor);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMaxAngularVelocity(IntPtr thisPtr, float maxVelocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetMaxAngularVelocity(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetCenterOfMass(IntPtr thisPtr, ref Vector3 position, ref Quaternion rotation);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetCenterOfMassPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetCenterOfMassRotation(IntPtr thisPtr, out Quaternion rotation);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPositionSolverCount(IntPtr thisPtr, int count);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetPositionSolverCount(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetVelocitySolverCount(IntPtr thisPtr, int count);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetVelocitySolverCount(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetInterpolationMode(IntPtr thisPtr, RigidbodyInterpolationMode value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern RigidbodyInterpolationMode Internal_GetInterpolationMode(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetFlags(IntPtr thisPtr, RigidbodyFlag flags);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern RigidbodyFlag Internal_GetFlags(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_AddForce(IntPtr thisPtr, ref Vector3 force, ForceMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_AddTorque(IntPtr thisPtr, ref Vector3 torque, ForceMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_AddForceAtPoint(IntPtr thisPtr, ref Vector3 force, ref Vector3 position, PointForceMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetVelocityAtPoint(IntPtr thisPtr, ref Vector3 point, out Vector3 velocity);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_AddCollider(IntPtr thisPtr, IntPtr collider);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_RemoveCollider(IntPtr thisPtr, IntPtr collider);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_RemoveColliders(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UpdateMassDistribution(IntPtr thisPtr);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native Rigidbody class.
+    /// <see cref="Rigidbody"/>
+    /// </summary>
+    internal class NativeRigidbody : ScriptObject
+    {
+        private Rigidbody component;
+
+        /// <summary>
+        /// Component that owns the native rigidbody object.
+        /// </summary>
+        public Rigidbody Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public Vector3 Position
+        {
+            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
+            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
+        }
+
+        public Quaternion Rotation
+        {
+            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
+            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
+        }
+
+        public float Mass
+        {
+            get { return Internal_GetMass(mCachedPtr); }
+            set { Internal_SetMass(mCachedPtr, value); }
+        }
+
+        public bool Kinematic
+        {
+            get { return Internal_GetIsKinematic(mCachedPtr); }
+            set { Internal_SetIsKinematic(mCachedPtr, value); }
+        }
+
+        public bool Sleeping
+        {
+            get { return Internal_IsSleeping(mCachedPtr); }
+            set
+            {
+                if (value)
+                    Internal_Sleep(mCachedPtr);
+                else
+                    Internal_WakeUp(mCachedPtr);
+            }
+        }
+
+        public float SleepThreshold
+        {
+            get { return Internal_GetSleepThreshold(mCachedPtr); }
+            set { Internal_SetSleepThreshold(mCachedPtr, value); }
+        }
+
+        public bool UseGravity
+        {
+            get { return Internal_GetUseGravity(mCachedPtr); }
+            set { Internal_SetUseGravity(mCachedPtr, value); }
+        }
+
+        public Vector3 Velocity
+        {
+            get { Vector3 velocity; Internal_GetVelocity(mCachedPtr, out velocity); return velocity; }
+            set { Internal_SetVelocity(mCachedPtr, ref value); }
+        }
+
+        public Vector3 AngularVelocity
+        {
+            get { Vector3 velocity; Internal_GetAngularVelocity(mCachedPtr, out velocity); return velocity; }
+            set { Internal_SetAngularVelocity(mCachedPtr, ref value); }
+        }
+
+        public float Drag
+        {
+            get { return Internal_GetDrag(mCachedPtr); }
+            set { Internal_SetDrag(mCachedPtr, value); }
+        }
+
+        public float AngularDrag
+        {
+            get { return Internal_GetAngularDrag(mCachedPtr); }
+            set { Internal_SetAngularDrag(mCachedPtr, value); }
+        }
+
+        public Vector3 InertiaTensor
+        {
+            get { Vector3 tensor; Internal_GetInertiaTensor(mCachedPtr, out tensor); return tensor; }
+            set { Internal_SetInertiaTensor(mCachedPtr, ref value); }
+        }
+
+        public Vector3 CenterOfMassPosition
+        {
+            get { Vector3 pos; Internal_GetCenterOfMassPosition(mCachedPtr, out pos); return pos; }
+            set { Quaternion rot = CenterOfMassRotation; Internal_SetCenterOfMass(mCachedPtr, ref value, ref rot); }
+        }
+
+        public Quaternion CenterOfMassRotation
+        {
+            get { Quaternion rot; Internal_GetCenterOfMassRotation(mCachedPtr, out rot); return rot; }
+            set { Vector3 pos = CenterOfMassPosition; Internal_SetCenterOfMass(mCachedPtr, ref pos, ref value); }
+        }
+
+        public float MaxAngularVelocity
+        {
+            get { return Internal_GetMaxAngularVelocity(mCachedPtr); }
+            set { Internal_SetMaxAngularVelocity(mCachedPtr, value); }
+        }
+
+        public int PositionSolverCount
+        {
+            get { return Internal_GetPositionSolverCount(mCachedPtr); }
+            set { Internal_SetPositionSolverCount(mCachedPtr, value); }
+        }
+
+        public int VelocitySolverCount
+        {
+            get { return Internal_GetVelocitySolverCount(mCachedPtr); }
+            set { Internal_SetVelocitySolverCount(mCachedPtr, value); }
+        }
+
+        public RigidbodyInterpolationMode InterpolationMode
+        {
+            get { return Internal_GetInterpolationMode(mCachedPtr); }
+            set { Internal_SetInterpolationMode(mCachedPtr, value); }
+        }
+
+        public RigidbodyFlag Flags
+        {
+            get { return Internal_GetFlags(mCachedPtr); }
+            set { Internal_SetFlags(mCachedPtr, value); }
+        }
+
+        public NativeRigidbody(SceneObject linkedSO)
+        {
+            IntPtr linkedSOPtr = IntPtr.Zero;
+            if (linkedSO != null)
+                linkedSOPtr = linkedSO.GetCachedPtr();
+
+            Internal_CreateInstance(this, linkedSOPtr);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        public void Move(Vector3 position)
+        {
+            Internal_Move(mCachedPtr, ref position);
+        }
+
+        public void Rotate(Quaternion rotation)
+        {
+            Internal_Rotate(mCachedPtr, ref rotation);
+        }
+
+        public void AddForce(Vector3 force, ForceMode mode)
+        {
+            Internal_AddForce(mCachedPtr, ref force, mode);
+        }
+
+        public void AddTorque(Vector3 torque, ForceMode mode)
+        {
+            Internal_AddTorque(mCachedPtr, ref torque, mode);
+        }
+
+        public void AddForceAtPoint(Vector3 force, Vector3 position, PointForceMode mode)
+        {
+            Internal_AddForceAtPoint(mCachedPtr, ref force, ref position, mode);
+        }
+
+        public Vector3 GetVelocityAtPoint(Vector3 position)
+        {
+            Vector3 velocity;
+            Internal_GetVelocityAtPoint(mCachedPtr, ref position, out velocity);
+            return velocity;
+        }
+
+        public void AddCollider(Collider collider)
+        {
+            if (collider == null)
+                return;
+
+            IntPtr colliderPtr = collider.native.GetCachedPtr();
+            Internal_AddCollider(mCachedPtr, colliderPtr);
+        }
+
+        public void RemoveCollider(Collider collider)
+        {
+            if (collider == null)
+                return;
+
+            IntPtr colliderPtr = collider.native.GetCachedPtr();
+            Internal_RemoveCollider(mCachedPtr, colliderPtr);
+        }
+
+        public void RemoveColliders()
+        {
+            Internal_RemoveColliders(mCachedPtr);
+        }
+
+        public void UpdateMassDistribution()
+        {
+            Internal_UpdateMassDistribution(mCachedPtr);
+        }
+
+        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
+        {
+            CollisionData collisionData;
+            collisionData.colliderA = scriptCollisionData.colliderA.Component;
+            collisionData.colliderB = scriptCollisionData.colliderB.Component;
+            collisionData.contactPoints = scriptCollisionData.contactPoints;
+
+            Component.DoOnCollisionBegin(collisionData);
+        }
+
+        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
+        {
+            CollisionData collisionData;
+            collisionData.colliderA = scriptCollisionData.colliderA.Component;
+            collisionData.colliderB = scriptCollisionData.colliderB.Component;
+            collisionData.contactPoints = scriptCollisionData.contactPoints;
+
+            Component.DoOnCollisionStay(collisionData);
+        }
+
+        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
+        {
+            CollisionData collisionData;
+            collisionData.colliderA = scriptCollisionData.colliderA.Component;
+            collisionData.colliderB = scriptCollisionData.colliderB.Component;
+            collisionData.contactPoints = scriptCollisionData.contactPoints;
+
+            Component.DoOnCollisionEnd(collisionData);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(NativeRigidbody instance, IntPtr linkedSO);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Rotate(IntPtr thisPtr, ref Quaternion rotation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rotation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetMass(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetIsKinematic(IntPtr thisPtr, bool kinematic);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetIsKinematic(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_IsSleeping(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Sleep(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_WakeUp(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSleepThreshold(IntPtr thisPtr, float threshold);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetSleepThreshold(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUseGravity(IntPtr thisPtr, bool gravity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetUseGravity(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetVelocity(IntPtr thisPtr, ref Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetVelocity(IntPtr thisPtr, out Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAngularVelocity(IntPtr thisPtr, ref Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetAngularVelocity(IntPtr thisPtr, out Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetDrag(IntPtr thisPtr, float drag);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetDrag(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAngularDrag(IntPtr thisPtr, float drag);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetAngularDrag(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetInertiaTensor(IntPtr thisPtr, ref Vector3 tensor);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetInertiaTensor(IntPtr thisPtr, out Vector3 tensor);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaxAngularVelocity(IntPtr thisPtr, float maxVelocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetMaxAngularVelocity(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetCenterOfMass(IntPtr thisPtr, ref Vector3 position, ref Quaternion rotation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetCenterOfMassPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetCenterOfMassRotation(IntPtr thisPtr, out Quaternion rotation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPositionSolverCount(IntPtr thisPtr, int count);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetPositionSolverCount(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetVelocitySolverCount(IntPtr thisPtr, int count);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetVelocitySolverCount(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetInterpolationMode(IntPtr thisPtr, RigidbodyInterpolationMode value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern RigidbodyInterpolationMode Internal_GetInterpolationMode(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetFlags(IntPtr thisPtr, RigidbodyFlag flags);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern RigidbodyFlag Internal_GetFlags(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_AddForce(IntPtr thisPtr, ref Vector3 force, ForceMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_AddTorque(IntPtr thisPtr, ref Vector3 torque, ForceMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_AddForceAtPoint(IntPtr thisPtr, ref Vector3 force, ref Vector3 position, PointForceMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetVelocityAtPoint(IntPtr thisPtr, ref Vector3 point, out Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_AddCollider(IntPtr thisPtr, IntPtr collider);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_RemoveCollider(IntPtr thisPtr, IntPtr collider);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_RemoveColliders(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UpdateMassDistribution(IntPtr thisPtr);
+    }
+}

+ 2 - 8
Source/MBansheeEngine/Physics/Rigidbody.cs

@@ -521,15 +521,9 @@ namespace BansheeEngine
             NotifyFlags = TransformChangedFlags.Transform | TransformChangedFlags.Parent;
         }
 
-        private void OnReset()
-        {
-            RestoreNative();
-        }
-
         private void OnEnable()
         {
-            if (native == null)
-                RestoreNative();
+            RestoreNative();
         }
 
         private void OnDisable()
@@ -583,13 +577,13 @@ namespace BansheeEngine
                 if (currentSO.GetComponent<Collider>() != null)
                 {
                     Collider[] colliders = currentSO.GetComponents<Collider>();
-
                     foreach (var entry in colliders)
                     {
                         if (!entry.IsValidParent(this))
                             continue;
 
                         entry.SetRigidbody(this, true);
+                        entry.native.Rigidbody = native;
 
                         children.Add(entry);
                         native.AddCollider(entry);