Browse Source

Refactor: SceneObject transform and non-component scene entities
- Transform is now a separate object that's shared by both scene object and non-component entities
- Non-component entities behavior is now generalized under the SceneActor class

BearishSun 8 years ago
parent
commit
890c449b74
82 changed files with 1853 additions and 1753 deletions
  1. 8 7
      Source/BansheeCore/Animation/BsAnimation.cpp
  2. 2 2
      Source/BansheeCore/Animation/BsAnimationManager.cpp
  3. 4 0
      Source/BansheeCore/BsCorePrerequisites.h
  4. 5 0
      Source/BansheeCore/CMakeSources.cmake
  5. 2 2
      Source/BansheeCore/Components/BsCAnimation.cpp
  6. 6 4
      Source/BansheeCore/Components/BsCAudioListener.cpp
  7. 2 2
      Source/BansheeCore/Components/BsCAudioSource.cpp
  8. 2 1
      Source/BansheeCore/Components/BsCBoxCollider.cpp
  9. 4 11
      Source/BansheeCore/Components/BsCCamera.cpp
  10. 3 2
      Source/BansheeCore/Components/BsCCapsuleCollider.cpp
  11. 3 3
      Source/BansheeCore/Components/BsCCharacterController.cpp
  12. 10 8
      Source/BansheeCore/Components/BsCCollider.cpp
  13. 9 6
      Source/BansheeCore/Components/BsCFixedJoint.cpp
  14. 3 2
      Source/BansheeCore/Components/BsCJoint.cpp
  15. 3 3
      Source/BansheeCore/Components/BsCLight.cpp
  16. 4 4
      Source/BansheeCore/Components/BsCLightProbeVolume.cpp
  17. 2 1
      Source/BansheeCore/Components/BsCMeshCollider.cpp
  18. 2 1
      Source/BansheeCore/Components/BsCPlaneCollider.cpp
  19. 3 3
      Source/BansheeCore/Components/BsCReflectionProbe.cpp
  20. 5 5
      Source/BansheeCore/Components/BsCRenderable.cpp
  21. 5 3
      Source/BansheeCore/Components/BsCRigidbody.cpp
  22. 6 3
      Source/BansheeCore/Components/BsCSliderJoint.cpp
  23. 2 1
      Source/BansheeCore/Components/BsCSphereCollider.cpp
  24. 15 17
      Source/BansheeCore/RTTI/BsCameraRTTI.h
  25. 4 3
      Source/BansheeCore/RTTI/BsLightProbeVolumeRTTI.h
  26. 13 12
      Source/BansheeCore/RTTI/BsLightRTTI.h
  27. 3 3
      Source/BansheeCore/RTTI/BsReflectionProbeRTTI.h
  28. 10 16
      Source/BansheeCore/RTTI/BsRenderableRTTI.h
  29. 7 10
      Source/BansheeCore/RTTI/BsSceneObjectRTTI.h
  30. 49 0
      Source/BansheeCore/RTTI/BsTransformRTTI.h
  31. 38 37
      Source/BansheeCore/Renderer/BsCamera.cpp
  32. 18 50
      Source/BansheeCore/Renderer/BsCamera.h
  33. 21 51
      Source/BansheeCore/Renderer/BsLight.cpp
  34. 4 71
      Source/BansheeCore/Renderer/BsLight.h
  35. 15 34
      Source/BansheeCore/Renderer/BsLightProbeVolume.cpp
  36. 6 51
      Source/BansheeCore/Renderer/BsLightProbeVolume.h
  37. 25 41
      Source/BansheeCore/Renderer/BsReflectionProbe.cpp
  38. 6 65
      Source/BansheeCore/Renderer/BsReflectionProbe.h
  39. 62 84
      Source/BansheeCore/Renderer/BsRenderable.cpp
  40. 20 61
      Source/BansheeCore/Renderer/BsRenderable.h
  41. 1 1
      Source/BansheeCore/Scene/BsComponent.cpp
  42. 8 6
      Source/BansheeCore/Scene/BsPrefabDiff.cpp
  43. 98 0
      Source/BansheeCore/Scene/BsSceneActor.cpp
  44. 112 0
      Source/BansheeCore/Scene/BsSceneActor.h
  45. 37 138
      Source/BansheeCore/Scene/BsSceneManager.cpp
  46. 71 93
      Source/BansheeCore/Scene/BsSceneManager.h
  47. 77 123
      Source/BansheeCore/Scene/BsSceneObject.cpp
  48. 19 64
      Source/BansheeCore/Scene/BsSceneObject.h
  49. 158 0
      Source/BansheeCore/Scene/BsTransform.cpp
  50. 171 0
      Source/BansheeCore/Scene/BsTransform.h
  51. 15 0
      Source/BansheeEditor/BsEditorApplication.cpp
  52. 3 0
      Source/BansheeEditor/BsEditorApplication.h
  53. 2 1
      Source/BansheeEditor/CodeEditor/BsMDCodeEditor.cpp
  54. 3 2
      Source/BansheeEditor/Handles/BsHandleDrawManager.cpp
  55. 3 2
      Source/BansheeEditor/Handles/BsHandleManager.cpp
  56. 4 2
      Source/BansheeEditor/Handles/BsHandleSlider.cpp
  57. 1 1
      Source/BansheeEditor/Handles/BsHandleSliderPlane.cpp
  58. 3 3
      Source/BansheeEditor/SceneView/BsGizmoManager.cpp
  59. 1 1
      Source/BansheeEditor/SceneView/BsSceneGrid.cpp
  60. 5 9
      Source/BansheeEditor/SceneView/BsScenePicking.cpp
  61. 6 8
      Source/BansheeEditor/SceneView/BsSelectionRenderer.cpp
  62. 3 3
      Source/BansheeEditor/Utility/BsEditorUtility.cpp
  63. 3 1
      Source/BansheeEngine/BsApplication.cpp
  64. 1 1
      Source/BansheeEngine/Debug/BsDebugDraw.cpp
  65. 5 4
      Source/BansheeEngine/GUI/BsGUIWidget.cpp
  66. 4 0
      Source/BansheeMono/BsMonoManager.cpp
  67. 4 2
      Source/BansheePhysX/BsPhysXRigidbody.cpp
  68. 1 1
      Source/BansheeUtility/FileSystem/BsPath.cpp
  69. 538 538
      Source/BansheeUtility/Math/BsMatrix3.cpp
  70. 15 15
      Source/BansheeUtility/Utility/BsDynLibManager.cpp
  71. 6 4
      Source/Examples/ExampleGettingStarted/CameraFlyer.cpp
  72. 6 4
      Source/Examples/ExamplePhysicallyBasedShading/CameraFlyer.cpp
  73. 3 2
      Source/RenderBeast/BsImageBasedLighting.cpp
  74. 3 2
      Source/RenderBeast/BsLightProbes.cpp
  75. 10 6
      Source/RenderBeast/BsLightRendering.cpp
  76. 3 3
      Source/RenderBeast/BsRendererObject.cpp
  77. 7 5
      Source/RenderBeast/BsRendererScene.cpp
  78. 12 10
      Source/RenderBeast/BsShadowRendering.cpp
  79. 5 3
      Source/SBansheeEngine/Wrappers/BsScriptScene.cpp
  80. 11 11
      Source/SBansheeEngine/Wrappers/BsScriptSceneObject.cpp
  81. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUI.cpp
  82. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIWidget.cpp

+ 8 - 7
Source/BansheeCore/Animation/BsAnimation.cpp

@@ -503,7 +503,7 @@ namespace bs
 				{
 					HSceneObject so = sceneObjects[i].so;
 					if (!so.isDestroyed(true))
-						invRootTransform = so->getWorldTfrm().inverseAffine();
+						invRootTransform = so->getWorldMatrix().inverseAffine();
 
 					break;
 				}				
@@ -554,7 +554,7 @@ namespace bs
 				else
 				{
 					// No need to check if SO is valid, if it has a bone connection it must be
-					sceneObjectTransforms[boneIdx] = so->getWorldTfrm() * invRootTransform;
+					sceneObjectTransforms[boneIdx] = so->getWorldMatrix() * invRootTransform;
 					boneIdx++;
 				}
 			}
@@ -602,7 +602,7 @@ namespace bs
 			{
 				HSceneObject so = sceneObjects[i].so;
 				if (!so.isDestroyed(true))
-					invRootTransform = so->getWorldTfrm().inverseAffine();
+					invRootTransform = so->getWorldMatrix().inverseAffine();
 
 				break;
 			}
@@ -623,7 +623,7 @@ namespace bs
 			if (sceneObjectInfos[i].boneIdx == -1)
 				continue;
 
-			sceneObjectTransforms[boneIdx] = sceneObjects[i].so->getWorldTfrm() * invRootTransform;
+			sceneObjectTransforms[boneIdx] = sceneObjects[i].so->getWorldMatrix() * invRootTransform;
 			boneIdx++;
 		}
 	}
@@ -1442,9 +1442,10 @@ namespace bs
 						HSceneObject rootParent = rootSO->getParent();
 						if(!rootParent.isDestroyed(true))
 						{
-							rootParentPos = rootParent->getWorldPosition();
-							rootParentRot = rootParent->getWorldRotation();
-							rootParentScale = rootParent->getWorldScale();
+							const Transform& tfrm = rootParent->getTransform();
+							rootParentPos = tfrm.getPosition();
+							rootParentRot = tfrm.getRotation();
+							rootParentScale = tfrm.getScale();
 						}
 					}
 

+ 2 - 2
Source/BansheeCore/Animation/BsAnimationManager.cpp

@@ -88,13 +88,13 @@ namespace bs
 		auto& allCameras = gSceneManager().getAllCameras();
 		for(auto& entry : allCameras)
 		{
-			bool isOverlayCamera = entry.second.camera->getRenderSettings()->overlayOnly;
+			bool isOverlayCamera = entry.second->getRenderSettings()->overlayOnly;
 			if (isOverlayCamera)
 				continue;
 
 			// TODO: Not checking if camera and animation renderable's layers match. If we checked more animations could
 			// be culled.
-			mCullFrustums.push_back(entry.second.camera->getWorldFrustum());
+			mCullFrustums.push_back(entry.second->getWorldFrustum());
 		}
 
 		// Make sure thread finishes writing all changes to the anim proxies as they will be read by the animation thread

+ 4 - 0
Source/BansheeCore/BsCorePrerequisites.h

@@ -346,6 +346,8 @@ namespace bs
 	class CReflectionProbe;
 	class CSkybox;
 	class CLightProbeVolume;
+	class Transform;
+	class SceneActor;
 	// Asset import
 	class SpecificImporter;
 	class Importer;
@@ -574,6 +576,8 @@ namespace bs
 		TID_LightProbeVolume = 1136,
 		TID_SavedLightProbeInfo = 1137,
 		TID_CLightProbeVolume = 1138,
+		TID_Transform = 1139,
+		TID_SceneActor = 1140,
 
 		// Moved from Engine layer
 		TID_CCamera = 30000,

+ 5 - 0
Source/BansheeCore/CMakeSources.cmake

@@ -80,6 +80,8 @@ set(BS_BANSHEECORE_INC_SCENE
 	"Scene/BsPrefab.h"
 	"Scene/BsPrefabDiff.h"
 	"Scene/BsPrefabUtility.h"
+	"Scene/BsTransform.h"
+	"Scene/BsSceneActor.h"
 )
 
 set(BS_BANSHEECORE_INC_INPUT
@@ -372,6 +374,7 @@ set(BS_BANSHEECORE_INC_RTTI
 	"RTTI/BsSkyboxRTTI.h"
 	"RTTI/BsLightProbeVolumeRTTI.h"
 	"RTTI/BsCLightProbeVolumeRTTI.h"
+	"RTTI/BsTransformRTTI.h"
 )
 
 set(BS_BANSHEECORE_SRC_RENDERER
@@ -529,6 +532,8 @@ set(BS_BANSHEECORE_SRC_SCENE
 	"Scene/BsPrefab.cpp"
 	"Scene/BsPrefabDiff.cpp"
 	"Scene/BsPrefabUtility.cpp"
+	"Scene/BsTransform.cpp"
+	"Scene/BsSceneActor.cpp"
 )
 
 set(BS_BANSHEECORE_INC_AUDIO

+ 2 - 2
Source/BansheeCore/Components/BsCAnimation.cpp

@@ -169,7 +169,7 @@ namespace bs
 
 					Matrix4 parentTfrm;
 					if (SO()->getParent() != nullptr)
-						parentTfrm = SO()->getParent()->getWorldTfrm();
+						parentTfrm = SO()->getParent()->getWorldMatrix();
 					else
 						parentTfrm = Matrix4::IDENTITY;
 
@@ -441,7 +441,7 @@ namespace bs
 			if (mInternal != nullptr)
 			{
 				AABox bounds = mBounds;
-				bounds.transformAffine(SO()->getWorldTfrm());
+				bounds.transformAffine(SO()->getWorldMatrix());
 
 				mInternal->setBounds(bounds);
 			}

+ 6 - 4
Source/BansheeCore/Components/BsCAudioListener.cpp

@@ -48,7 +48,7 @@ namespace bs
 
 	void CAudioListener::update()
 	{
-		Vector3 worldPos = SO()->getWorldPosition();
+		Vector3 worldPos = SO()->getTransform().getPosition();
 		mVelocity = (worldPos - mLastPosition) / gTime().getFrameDelta();
 		mLastPosition = worldPos;
 	}
@@ -69,9 +69,11 @@ namespace bs
 	
 	void CAudioListener::updateTransform()
 	{
-		mInternal->setPosition(SO()->getWorldPosition());
-		mInternal->setDirection(SO()->getForward());
-		mInternal->setUp(SO()->getUp());
+		const Transform& tfrm = SO()->getTransform();
+
+		mInternal->setPosition(tfrm.getPosition());
+		mInternal->setDirection(tfrm.getForward());
+		mInternal->setUp(tfrm.getUp());
 		mInternal->setVelocity(mVelocity);
 	}
 	

+ 2 - 2
Source/BansheeCore/Components/BsCAudioSource.cpp

@@ -169,7 +169,7 @@ namespace bs
 
 	void CAudioSource::update()
 	{
-		Vector3 worldPos = SO()->getWorldPosition();
+		Vector3 worldPos = SO()->getTransform().getPosition();
 		mVelocity = (worldPos - mLastPosition) / gTime().getFrameDelta();
 		mLastPosition = worldPos;
 	}
@@ -199,7 +199,7 @@ namespace bs
 
 	void CAudioSource::updateTransform()
 	{
-		mInternal->setPosition(SO()->getWorldPosition());
+		mInternal->setPosition(SO()->getTransform().getPosition());
 		mInternal->setVelocity(mVelocity);
 	}
 

+ 2 - 1
Source/BansheeCore/Components/BsCBoxCollider.cpp

@@ -44,7 +44,8 @@ namespace bs
 
 	SPtr<Collider> CBoxCollider::createInternal()
 	{
-		SPtr<Collider> collider = BoxCollider::create(mExtents, SO()->getWorldPosition(), SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		SPtr<Collider> collider = BoxCollider::create(mExtents, tfrm.getPosition(), tfrm.getRotation());
 		collider->_setOwner(PhysicsOwnerType::Component, this);
 
 		return collider;

+ 4 - 11
Source/BansheeCore/Components/BsCCamera.cpp

@@ -32,7 +32,7 @@ namespace bs
 	ConvexVolume CCamera::getWorldFrustum() const
 	{
 		const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
-		Matrix4 worldMatrix = SO()->getWorldTfrm();
+		Matrix4 worldMatrix = SO()->getWorldMatrix();
 
 		Vector<Plane> worldPlanes(frustumPlanes.size());
 		UINT32 i = 0;
@@ -47,14 +47,7 @@ namespace bs
 
 	void CCamera::updateView() const
 	{
-		UINT32 curHash = SO()->getTransformHash();
-		if (curHash != mInternal->_getLastModifiedHash())
-		{
-			mInternal->setPosition(SO()->getWorldPosition());
-			mInternal->setRotation(SO()->getWorldRotation());
-
-			mInternal->_setLastModifiedHash(curHash);
-		}
+		mInternal->_updateState(*SO());
 	}
 
 	void CCamera::setMain(bool main)
@@ -81,12 +74,12 @@ namespace bs
 			mTarget = nullptr;
 		}
 
-		gSceneManager()._registerCamera(mInternal, SO());
+		gSceneManager()._bindActor(mInternal, SO());
 	}
 
 	void CCamera::onDestroyed()
 	{
-		gSceneManager()._unregisterCamera(mInternal);
+		gSceneManager()._unbindActor(mInternal);
 	}
 
 	RTTITypeBase* CCamera::getRTTIStatic()

+ 3 - 2
Source/BansheeCore/Components/BsCCapsuleCollider.cpp

@@ -74,8 +74,9 @@ namespace bs
 
 	SPtr<Collider> CCapsuleCollider::createInternal()
 	{
-		SPtr<Collider> collider = CapsuleCollider::create(mRadius, mHalfHeight, SO()->getWorldPosition(), 
-			SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		SPtr<Collider> collider = CapsuleCollider::create(mRadius, mHalfHeight, tfrm.getPosition(), 
+			tfrm.getRotation());
 
 		collider->_setOwner(PhysicsOwnerType::Component, this);
 		return collider;

+ 3 - 3
Source/BansheeCore/Components/BsCCharacterController.cpp

@@ -144,7 +144,7 @@ namespace bs
 
 	void CCharacterController::onEnabled()
 	{
-		mDesc.position = SO()->getWorldPosition();
+		mDesc.position = SO()->getTransform().getPosition();
 		mInternal = CharacterController::create(mDesc);
 		mInternal->_setOwner(PhysicsOwnerType::Component, this);
 
@@ -160,7 +160,7 @@ namespace bs
 		if (!SO()->getActive() || mInternal == nullptr)
 			return;
 
-		mInternal->setPosition(SO()->getWorldPosition());
+		mInternal->setPosition(SO()->getTransform().getPosition());
 	}
 
 	void CCharacterController::updatePositionFromController()
@@ -172,7 +172,7 @@ namespace bs
 
 	void CCharacterController::updateDimensions()
 	{
-		Vector3 scale = SO()->getWorldScale();
+		Vector3 scale = SO()->getTransform().getScale();
 		float height = mDesc.height * Math::abs(scale.y);
 		float radius = mDesc.radius * Math::abs(std::max(scale.x, scale.z));
 

+ 10 - 8
Source/BansheeCore/Components/BsCCollider.cpp

@@ -240,17 +240,19 @@ namespace bs
 
 	void CCollider::updateTransform()
 	{
-		Vector3 myScale = SO()->getWorldScale();
+		const Transform& tfrm = SO()->getTransform();
+		Vector3 myScale = tfrm.getScale();
 
 		if (mParent != nullptr)
 		{
-			Vector3 parentPos = mParent->SO()->getWorldPosition();
-			Quaternion parentRot = mParent->SO()->getWorldRotation();
+			const Transform& parentTfrm = mParent->SO()->getTransform();
+			Vector3 parentPos = parentTfrm.getPosition();
+			Quaternion parentRot = parentTfrm.getRotation();
 
-			Vector3 myPos = SO()->getWorldPosition();
-			Quaternion myRot = SO()->getWorldRotation();
+			Vector3 myPos = tfrm.getPosition();
+			Quaternion myRot = tfrm.getRotation();
 
-			Vector3 scale = mParent->SO()->getWorldScale();
+			Vector3 scale = parentTfrm.getScale();
 			Vector3 invScale = scale;
 			if (invScale.x != 0) invScale.x = 1.0f / invScale.x;
 			if (invScale.y != 0) invScale.y = 1.0f / invScale.y;
@@ -269,8 +271,8 @@ namespace bs
 		}
 		else
 		{
-			Quaternion myRot = SO()->getWorldRotation();
-			Vector3 myPos = SO()->getWorldPosition() + myRot.rotate(mLocalPosition * myScale);
+			Quaternion myRot = tfrm.getRotation();
+			Vector3 myPos = tfrm.getPosition() + myRot.rotate(mLocalPosition * myScale);
 			myRot = myRot * mLocalRotation;
 
 			mInternal->setTransform(myPos, myRot);

+ 9 - 6
Source/BansheeCore/Components/BsCFixedJoint.cpp

@@ -31,26 +31,29 @@ namespace bs
 		rotation = mRotations[(int)body];
 
 		HRigidbody rigidbody = mBodies[(int)body];
+		const Transform& tfrm = SO()->getTransform();
 		if (rigidbody == nullptr) // Get world space transform if no relative to any body
 		{
-			Quaternion worldRot = SO()->getWorldRotation();
+			Quaternion worldRot = tfrm.getRotation();
 
 			rotation = worldRot*rotation;
-			position = worldRot.rotate(position) + SO()->getWorldPosition();
+			position = worldRot.rotate(position) + tfrm.getPosition();
 		}
 		else
 		{
+			const Transform& rigidbodyTfrm = rigidbody->SO()->getTransform();
+
 			// Find world space transform
-			Quaternion worldRot = rigidbody->SO()->getWorldRotation();
+			Quaternion worldRot = rigidbodyTfrm.getRotation();
 
 			rotation = worldRot * rotation;
-			position = worldRot.rotate(position) + rigidbody->SO()->getWorldPosition();
+			position = worldRot.rotate(position) + rigidbodyTfrm.getPosition();
 
 			// Get transform of the joint local to the object
 			Quaternion invRotation = rotation.inverse();
 
-			position = invRotation.rotate(SO()->getWorldPosition() - position);
-			rotation = invRotation * SO()->getWorldRotation();
+			position = invRotation.rotate(tfrm.getPosition() - position);
+			rotation = invRotation * tfrm.getRotation();
 		}
 	}
 

+ 3 - 2
Source/BansheeCore/Components/BsCJoint.cpp

@@ -266,10 +266,11 @@ namespace bs
 		HRigidbody rigidbody = mBodies[(int)body];
 		if (rigidbody == nullptr) // Get world space transform if no relative to any body
 		{
-			Quaternion worldRot = SO()->getWorldRotation();
+			const Transform& tfrm = SO()->getTransform();
+			Quaternion worldRot = tfrm.getRotation();
 
 			rotation = worldRot*rotation;
-			position = worldRot.rotate(position) + SO()->getWorldPosition();
+			position = worldRot.rotate(position) + tfrm.getPosition();
 		}
 		else
 		{

+ 3 - 3
Source/BansheeCore/Components/BsCLight.cpp

@@ -29,7 +29,7 @@ namespace bs
 
 	Sphere CLight::getBounds() const
 	{
-		mInternal->_updateTransform(SO());
+		mInternal->_updateState(*SO());
 
 		return mInternal->getBounds();
 	}
@@ -46,12 +46,12 @@ namespace bs
 				mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
 		}
 
-		gSceneManager()._registerLight(mInternal, sceneObject());
+		gSceneManager()._bindActor(mInternal, sceneObject());
 	}
 
 	void CLight::onDestroyed()
 	{
-		gSceneManager()._unregisterLight(mInternal);
+		gSceneManager()._unbindActor(mInternal);
 	}
 	
 	RTTITypeBase* CLight::getRTTIStatic()

+ 4 - 4
Source/BansheeCore/Components/BsCLightProbeVolume.cpp

@@ -29,7 +29,7 @@ namespace bs
 	{
 		if (mInternal != nullptr && SO()->getActive())
 		{
-			mInternal->_updateTransform(SO());
+			mInternal->_updateState(*SO());
 			mInternal->renderProbe(handle);
 		}
 	}
@@ -38,7 +38,7 @@ namespace bs
 	{
 		if (mInternal != nullptr && SO()->getActive())
 		{
-			mInternal->_updateTransform(SO());
+			mInternal->_updateState(*SO());
 			mInternal->renderProbes();
 		}
 	}
@@ -60,12 +60,12 @@ namespace bs
 		else
 			mInternal = LightProbeVolume::create(mVolume, mCellCount);
 
-		gSceneManager()._registerLightProbeVolume(mInternal, sceneObject());
+		gSceneManager()._bindActor(mInternal, sceneObject());
 	}
 
 	void CLightProbeVolume::onDestroyed()
 	{
-		gSceneManager()._unregisterLightProbeVolume(mInternal);
+		gSceneManager()._unbindActor(mInternal);
 	}
 	
 	RTTITypeBase* CLightProbeVolume::getRTTIStatic()

+ 2 - 1
Source/BansheeCore/Components/BsCMeshCollider.cpp

@@ -45,7 +45,8 @@ namespace bs
 
 	SPtr<Collider> CMeshCollider::createInternal()
 	{
-		SPtr<MeshCollider> collider = MeshCollider::create(SO()->getWorldPosition(), SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		SPtr<MeshCollider> collider = MeshCollider::create(tfrm.getPosition(), tfrm.getRotation());
 		collider->setMesh(mMesh);
 		collider->_setOwner(PhysicsOwnerType::Component, this);
 

+ 2 - 1
Source/BansheeCore/Components/BsCPlaneCollider.cpp

@@ -42,7 +42,8 @@ namespace bs
 
 	SPtr<Collider> CPlaneCollider::createInternal()
 	{
-		SPtr<Collider> collider = PlaneCollider::create(SO()->getWorldPosition(), SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		SPtr<Collider> collider = PlaneCollider::create(tfrm.getPosition(), tfrm.getRotation());
 
 		collider->_setOwner(PhysicsOwnerType::Component, this);
 		return collider;

+ 3 - 3
Source/BansheeCore/Components/BsCReflectionProbe.cpp

@@ -26,7 +26,7 @@ namespace bs
 
 	Sphere CReflectionProbe::getBounds() const
 	{
-		mInternal->_updateTransform(SO());
+		mInternal->_updateState(*SO());
 
 		return mInternal->getBounds();
 	}
@@ -40,7 +40,7 @@ namespace bs
 		else
 			mInternal = ReflectionProbe::createBox(Vector3::ONE);
 
-		gSceneManager()._registerReflectionProbe(mInternal, sceneObject());
+		gSceneManager()._bindActor(mInternal, sceneObject());
 
 		// If filtered texture doesn't exist, ensure it is generated
 		SPtr<Texture> filteredTexture = mInternal->getFilteredTexture();
@@ -55,7 +55,7 @@ namespace bs
 
 	void CReflectionProbe::onDestroyed()
 	{
-		gSceneManager()._unregisterReflectionProbe(mInternal);
+		gSceneManager()._unbindActor(mInternal);
 	}
 
 	RTTITypeBase* CReflectionProbe::getRTTIStatic()

+ 5 - 5
Source/BansheeCore/Components/BsCRenderable.cpp

@@ -41,7 +41,7 @@ namespace bs
 		else
 			mInternal = Renderable::create();
 
-		gSceneManager()._registerRenderable(mInternal, sceneObject());
+		gSceneManager()._bindActor(mInternal, sceneObject());
 
 		mAnimation = SO()->getComponent<CAnimation>();
 		if (mAnimation != nullptr)
@@ -53,7 +53,7 @@ namespace bs
 
 	Bounds CRenderable::getBounds() const
 	{
-		mInternal->_updateTransform(mThisHandle);
+		mInternal->_updateState(*SO());
 		return mInternal->getBounds();
 	}
 
@@ -74,7 +74,7 @@ namespace bs
 
 			// Need to update transform because animated renderables handle local transforms through bones, so it
 			// shouldn't be included in the renderable's transform.
-			mInternal->_updateTransform(SO(), true);
+			mInternal->_updateState(*SO(), true);
 		}
 	}
 
@@ -88,7 +88,7 @@ namespace bs
 
 			// Need to update transform because animated renderables handle local transforms through bones, so it
 			// shouldn't be included in the renderable's transform.
-			mInternal->_updateTransform(SO(), true);
+			mInternal->_updateState(*SO(), true);
 		}
 	}
 
@@ -102,7 +102,7 @@ namespace bs
 		if (mAnimation != nullptr)
 			mAnimation->_unregisterRenderable();
 
-		gSceneManager()._unregisterRenderable(mInternal);
+		gSceneManager()._unbindActor(mInternal);
 	}
 
 	RTTITypeBase* CRenderable::getRTTIStatic()

+ 5 - 3
Source/BansheeCore/Components/BsCRigidbody.cpp

@@ -442,7 +442,8 @@ namespace bs
 		mInternal->onCollisionStay.connect(std::bind(&CRigidbody::triggerOnCollisionStay, this, _1));
 		mInternal->onCollisionEnd.connect(std::bind(&CRigidbody::triggerOnCollisionEnd, this, _1));
 
-		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		mInternal->setTransform(tfrm.getPosition(), tfrm.getRotation());
 
 		// Note: Merge into one call to avoid many virtual function calls
 		mInternal->setPositionSolverCount(mPositionSolverCount);
@@ -487,8 +488,9 @@ namespace bs
 			checkForNestedRigibody();
 #endif
 		}
-
-		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+		
+		const Transform& tfrm = SO()->getTransform();
+		mInternal->setTransform(tfrm.getPosition(), tfrm.getRotation());
 
 		if (mParentJoint != nullptr)
 			mParentJoint->notifyRigidbodyMoved(mThisHandle);

+ 6 - 3
Source/BansheeCore/Components/BsCSliderJoint.cpp

@@ -83,20 +83,23 @@ namespace bs
 		rotation = mRotations[(int)body];
 
 		HRigidbody rigidbody = mBodies[(int)body];
+		const Transform& tfrm = SO()->getTransform();
 		if (rigidbody == nullptr) // Get world space transform if no relative to any body
 		{
-			Quaternion worldRot = SO()->getWorldRotation();
+			Quaternion worldRot = tfrm.getRotation();
 
 			rotation = worldRot*rotation;
-			position = worldRot.rotate(position) + SO()->getWorldPosition();
+			position = worldRot.rotate(position) + tfrm.getPosition();
 		}
 		else
 		{
+			const Transform& rigidbodyTfrm = rigidbody->SO()->getTransform();
+
 			// Use only the offset for positioning, but for rotation use both the offset and target SO rotation.
 			// (Needed because we need to rotate the joint SO in order to orient the slider direction, so we need an
 			// additional transform that allows us to orient the object)
 			position = rotation.rotate(position);
-			rotation = (rigidbody->SO()->getWorldRotation()*rotation).inverse()*SO()->getWorldRotation();
+			rotation = (rigidbodyTfrm.getRotation()*rotation).inverse()*tfrm.getRotation();
 		}
 	}
 

+ 2 - 1
Source/BansheeCore/Components/BsCSphereCollider.cpp

@@ -43,7 +43,8 @@ namespace bs
 
 	SPtr<Collider> CSphereCollider::createInternal()
 	{
-		SPtr<Collider> collider = SphereCollider::create(mRadius, SO()->getWorldPosition(), SO()->getWorldRotation());
+		const Transform& tfrm = SO()->getTransform();
+		SPtr<Collider> collider = SphereCollider::create(mRadius, tfrm.getPosition(), tfrm.getRotation());
 
 		collider->_setOwner(PhysicsOwnerType::Component, this);
 		return collider;

+ 15 - 17
Source/BansheeCore/RTTI/BsCameraRTTI.h

@@ -19,18 +19,19 @@ namespace bs
 		BS_BEGIN_RTTI_MEMBERS
 			BS_RTTI_MEMBER_REFLPTR(mViewport, 0)
 			BS_RTTI_MEMBER_PLAIN(mLayers, 1)
-			BS_RTTI_MEMBER_PLAIN(mPosition, 2)
-			BS_RTTI_MEMBER_PLAIN(mRotation, 3)
-			BS_RTTI_MEMBER_PLAIN(mProjType, 4)
-			BS_RTTI_MEMBER_PLAIN(mHorzFOV, 5)
-			BS_RTTI_MEMBER_PLAIN(mFarDist, 6)
-			BS_RTTI_MEMBER_PLAIN(mNearDist, 7)
-			BS_RTTI_MEMBER_PLAIN(mAspect, 8)
-			BS_RTTI_MEMBER_PLAIN(mOrthoHeight, 9)
-			BS_RTTI_MEMBER_PLAIN(mPriority, 10)
-			BS_RTTI_MEMBER_PLAIN(mCustomViewMatrix, 11)
-			BS_RTTI_MEMBER_PLAIN(mCustomProjMatrix, 12)
-			BS_RTTI_MEMBER_PLAIN(mFrustumExtentsManuallySet, 13)
+			BS_RTTI_MEMBER_REFL(mTransform, 2)
+			BS_RTTI_MEMBER_PLAIN(mActive, 3)
+			BS_RTTI_MEMBER_PLAIN(mMobility, 4)
+			BS_RTTI_MEMBER_PLAIN(mProjType, 5)
+			BS_RTTI_MEMBER_PLAIN(mHorzFOV, 6)
+			BS_RTTI_MEMBER_PLAIN(mFarDist, 7)
+			BS_RTTI_MEMBER_PLAIN(mNearDist, 8)
+			BS_RTTI_MEMBER_PLAIN(mAspect, 9)
+			BS_RTTI_MEMBER_PLAIN(mOrthoHeight, 10)
+			BS_RTTI_MEMBER_PLAIN(mPriority, 11)
+			BS_RTTI_MEMBER_PLAIN(mCustomViewMatrix, 12)
+			BS_RTTI_MEMBER_PLAIN(mCustomProjMatrix, 13)
+			BS_RTTI_MEMBER_PLAIN(mFrustumExtentsManuallySet, 14)
 			BS_RTTI_MEMBER_PLAIN(mProjMatrixRS, 15)
 			BS_RTTI_MEMBER_PLAIN(mProjMatrix, 16)
 			BS_RTTI_MEMBER_PLAIN(mViewMatrix, 17)
@@ -38,11 +39,8 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(mRight, 19)
 			BS_RTTI_MEMBER_PLAIN(mTop, 20)
 			BS_RTTI_MEMBER_PLAIN(mBottom, 21)
-			//BS_RTTI_MEMBER_PLAIN(mCameraFlags, 22)
-			BS_RTTI_MEMBER_PLAIN(mMSAA, 23)
-			/** BS_RTTI_MEMBER_PLAIN(mPPSettings, 24) */
-			BS_RTTI_MEMBER_REFLPTR(mRenderSettings, 25)
-			/** BS_RTTI_MEMBER_REFL(mSkyTexture, 26) */
+			BS_RTTI_MEMBER_PLAIN(mMSAA, 22)
+			BS_RTTI_MEMBER_REFLPTR(mRenderSettings, 23)
 		BS_END_RTTI_MEMBERS
 			
 	public:

+ 4 - 3
Source/BansheeCore/RTTI/BsLightProbeVolumeRTTI.h

@@ -86,8 +86,9 @@ namespace bs
 	{
 	private:
 		BS_BEGIN_RTTI_MEMBERS
-			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
-			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
+			BS_RTTI_MEMBER_REFL(mTransform, 0)
+			BS_RTTI_MEMBER_PLAIN(mActive, 1)
+			BS_RTTI_MEMBER_PLAIN(mMobility, 2)
 			BS_RTTI_MEMBER_PLAIN(mVolume, 3)
 			BS_RTTI_MEMBER_PLAIN(mCellCount, 4)
 		BS_END_RTTI_MEMBERS
@@ -136,7 +137,7 @@ namespace bs
 			:mInitMembers(this)
 		{
 			
-			addPlainField("mProbeInfo", 2, &LightProbeVolumeRTTI::getProbeInfo, &LightProbeVolumeRTTI::setProbeInfo, 
+			addPlainField("mProbeInfo", 5, &LightProbeVolumeRTTI::getProbeInfo, &LightProbeVolumeRTTI::setProbeInfo, 
 				RTTI_Flag_SkipInReferenceSearch);
 		}
 

+ 13 - 12
Source/BansheeCore/RTTI/BsLightRTTI.h

@@ -17,18 +17,19 @@ namespace bs
 	{
 	private:
 		BS_BEGIN_RTTI_MEMBERS
-			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
-			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
-			BS_RTTI_MEMBER_PLAIN(mType, 2)
-			BS_RTTI_MEMBER_PLAIN(mCastsShadows, 3)
-			BS_RTTI_MEMBER_PLAIN(mColor, 4)
-			BS_RTTI_MEMBER_PLAIN(mAttRadius, 5)
-			BS_RTTI_MEMBER_PLAIN(mIntensity, 6)
-			BS_RTTI_MEMBER_PLAIN(mSpotAngle, 7)
-			BS_RTTI_MEMBER_PLAIN(mSpotFalloffAngle, 8)
-			BS_RTTI_MEMBER_PLAIN(mAutoAttenuation, 9)
-			BS_RTTI_MEMBER_PLAIN(mSourceRadius, 10)
-			BS_RTTI_MEMBER_PLAIN(mShadowBias, 11)
+			BS_RTTI_MEMBER_REFL(mTransform, 0)
+			BS_RTTI_MEMBER_PLAIN(mActive, 1)
+			BS_RTTI_MEMBER_PLAIN(mMobility, 2)
+			BS_RTTI_MEMBER_PLAIN(mType, 3)
+			BS_RTTI_MEMBER_PLAIN(mCastsShadows, 4)
+			BS_RTTI_MEMBER_PLAIN(mColor, 5)
+			BS_RTTI_MEMBER_PLAIN(mAttRadius, 6)
+			BS_RTTI_MEMBER_PLAIN(mIntensity, 7)
+			BS_RTTI_MEMBER_PLAIN(mSpotAngle, 8)
+			BS_RTTI_MEMBER_PLAIN(mSpotFalloffAngle, 9)
+			BS_RTTI_MEMBER_PLAIN(mAutoAttenuation, 10)
+			BS_RTTI_MEMBER_PLAIN(mSourceRadius, 11)
+			BS_RTTI_MEMBER_PLAIN(mShadowBias, 12)
 		BS_END_RTTI_MEMBERS
 	public:
 		LightRTTI()

+ 3 - 3
Source/BansheeCore/RTTI/BsReflectionProbeRTTI.h

@@ -18,9 +18,9 @@ namespace bs
 	{
 	private:
 		BS_BEGIN_RTTI_MEMBERS
-			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
-			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
-			BS_RTTI_MEMBER_PLAIN(mScale, 2)
+			BS_RTTI_MEMBER_REFL(mTransform, 0)
+			BS_RTTI_MEMBER_PLAIN(mActive, 1)
+			BS_RTTI_MEMBER_PLAIN(mMobility, 2)
 			BS_RTTI_MEMBER_PLAIN(mType, 3)
 			BS_RTTI_MEMBER_PLAIN(mRadius, 4)
 			BS_RTTI_MEMBER_PLAIN(mExtents, 5)

+ 10 - 16
Source/BansheeCore/RTTI/BsRenderableRTTI.h

@@ -16,25 +16,19 @@ namespace bs
 	class BS_CORE_EXPORT RenderableRTTI : public RTTIType<Renderable, IReflectable, RenderableRTTI>
 	{
 	private:
-		HMesh& getMesh(Renderable* obj) { return obj->mMesh; }
-		void setMesh(Renderable* obj, HMesh& val) { obj->mMesh = val; }
-
-		UINT64& getLayer(Renderable* obj) { return obj->mLayer; }
-		void setLayer(Renderable* obj, UINT64& val) { obj->mLayer = val; }
-
-		HMaterial& getMaterial(Renderable* obj, UINT32 idx) { return obj->mMaterials[idx]; }
-		void setMaterial(Renderable* obj, UINT32 idx, HMaterial& val) { obj->setMaterial(idx, val); }
-		UINT32 getNumMaterials(Renderable* obj) { return (UINT32)obj->mMaterials.size(); }
-		void setNumMaterials(Renderable* obj, UINT32 num) { obj->mMaterials.resize(num); }
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_REFL(mTransform, 0)
+			BS_RTTI_MEMBER_PLAIN(mActive, 1)
+			BS_RTTI_MEMBER_PLAIN(mMobility, 2)
+			BS_RTTI_MEMBER_REFL(mMesh, 3)
+			BS_RTTI_MEMBER_PLAIN(mLayer, 4)
+			BS_RTTI_MEMBER_REFL_ARRAY(mMaterials, 5)
+		BS_END_RTTI_MEMBERS
 
 	public:
 		RenderableRTTI()
-		{
-			addReflectableField("mMesh", 0, &RenderableRTTI::getMesh, &RenderableRTTI::setMesh);
-			addPlainField("mLayer", 1, &RenderableRTTI::getLayer, &RenderableRTTI::setLayer);
-			addReflectableArrayField("mMaterials", 2, &RenderableRTTI::getMaterial, 
-				&RenderableRTTI::getNumMaterials, &RenderableRTTI::setMaterial, &RenderableRTTI::setNumMaterials);
-		}
+			:mInitMembers(this)
+		{ }
 
 		void onDeserializationEnded(IReflectable* obj, const UnorderedMap<String, UINT64>& params) override
 		{

+ 7 - 10
Source/BansheeCore/RTTI/BsSceneObjectRTTI.h

@@ -28,14 +28,11 @@ namespace bs
 	class BS_CORE_EXPORT SceneObjectRTTI : public RTTIType<SceneObject, GameObject, SceneObjectRTTI>
 	{
 	private:
-		Vector3& getPosition(SceneObject* obj) { return obj->mPosition; }
-		void setPosition(SceneObject* obj, Vector3& value) { obj->mPosition = value; }
+		Transform& getTransform(SceneObject* obj) { return obj->mWorldTfrm; }
+		void setTransform(SceneObject* obj, Transform& value) { obj->mWorldTfrm = value; }
 
-		Quaternion& getRotation(SceneObject* obj) { return obj->mRotation; }
-		void setRotation(SceneObject* obj, Quaternion& value) { obj->mRotation = value; }
-
-		Vector3& getScale(SceneObject* obj) { return obj->mScale; }
-		void setScale(SceneObject* obj, Vector3& value) { obj->mScale = value; }
+		Transform& getLocalTransform(SceneObject* obj) { return obj->mLocalTfrm; }
+		void setLocalTransform(SceneObject* obj, Transform& value) { obj->mLocalTfrm = value; }
 
 		bool& getActive(SceneObject* obj) { return obj->mActiveSelf; }
 		void setActive(SceneObject* obj, bool& value) { obj->mActiveSelf = value; }
@@ -101,11 +98,11 @@ namespace bs
 			addPlainField("mFlags", 3, &SceneObjectRTTI::getFlags, &SceneObjectRTTI::setFlags);
 			addReflectablePtrField("mPrefabDiff", 4, &SceneObjectRTTI::getPrefabDiff, &SceneObjectRTTI::setPrefabDiff);
 			addPlainField("mPrefabHash", 5, &SceneObjectRTTI::getPrefabHash, &SceneObjectRTTI::setPrefabHash);
-			addPlainField("mPosition", 6, &SceneObjectRTTI::getPosition, &SceneObjectRTTI::setPosition);
-			addPlainField("mRotation", 7, &SceneObjectRTTI::getRotation, &SceneObjectRTTI::setRotation);
-			addPlainField("mScale", 8, &SceneObjectRTTI::getScale, &SceneObjectRTTI::setScale);
 			addPlainField("mActiveSelf", 9, &SceneObjectRTTI::getActive, &SceneObjectRTTI::setActive);
 			addPlainField("mMobility", 10, &SceneObjectRTTI::getMobility, &SceneObjectRTTI::setMobility);
+
+			addReflectableField("mWorldTfrm", 11, &SceneObjectRTTI::getTransform, &SceneObjectRTTI::setTransform);
+			addReflectableField("mLocalTfrm", 12, &SceneObjectRTTI::getLocalTransform, &SceneObjectRTTI::setLocalTransform);
 		}
 
 		void onDeserializationStarted(IReflectable* obj, const UnorderedMap<String, UINT64>& params) override

+ 49 - 0
Source/BansheeCore/RTTI/BsTransformRTTI.h

@@ -0,0 +1,49 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "Reflection/BsRTTIType.h"
+#include "Scene/BsTransform.h"
+
+namespace bs
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Core
+	 *  @{
+	 */
+
+	class BS_CORE_EXPORT TransformRTTI : public RTTIType<Transform, IReflectable, TransformRTTI>
+	{
+	private:
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
+			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
+			BS_RTTI_MEMBER_PLAIN(mScale, 2)
+		BS_END_RTTI_MEMBERS
+
+	public:
+		TransformRTTI()
+			:mInitMembers(this)
+		{ }
+
+		const String& getRTTIName() override
+		{
+			static String name = "Transform";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_Transform;
+		}
+
+		SPtr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<Transform>();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 38 - 37
Source/BansheeCore/Renderer/BsCamera.cpp

@@ -13,18 +13,18 @@
 #include "Renderer/BsRendererManager.h"
 #include "Renderer/BsRenderer.h"
 #include "Allocators/BsFrameAlloc.h"
+#include "Scene/BsSceneManager.h"
 
 namespace bs
 {
 	const float CameraBase::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
 
 	CameraBase::CameraBase()
-		: mLayers(0xFFFFFFFFFFFFFFFF), mPosition(BsZero), mRotation(BsIdentity)
-		, mIsActive(true), mProjType(PT_PERSPECTIVE), mHorzFOV(Degree(90.0f)), mFarDist(1000.0f), mNearDist(0.05f)
-		, mAspect(1.33333333333333f), mOrthoHeight(5), mPriority(0), mCustomViewMatrix(false), mCustomProjMatrix(false)
-		, mMSAA(1), mFrustumExtentsManuallySet(false), mProjMatrixRS(BsZero), mProjMatrix(BsZero), mViewMatrix(BsZero)
-		, mProjMatrixRSInv(BsZero), mProjMatrixInv(BsZero), mViewMatrixInv(BsZero), mRecalcFrustum(true)
-		, mRecalcFrustumPlanes(true), mRecalcView(true)
+		: mLayers(0xFFFFFFFFFFFFFFFF), mProjType(PT_PERSPECTIVE), mHorzFOV(Degree(90.0f)), mFarDist(1000.0f)
+		, mNearDist(0.05f), mAspect(1.33333333333333f), mOrthoHeight(5), mPriority(0), mCustomViewMatrix(false)
+		, mCustomProjMatrix(false), mMSAA(1), mFrustumExtentsManuallySet(false), mProjMatrixRS(BsZero), mProjMatrix(BsZero)
+		, mViewMatrix(BsZero), mProjMatrixRSInv(BsZero), mProjMatrixInv(BsZero), mViewMatrixInv(BsZero)
+		, mRecalcFrustum(true), mRecalcFrustumPlanes(true), mRecalcView(true)
 	{
 		mRenderSettings = bs_shared_ptr_new<RenderSettings>();
 
@@ -60,7 +60,7 @@ namespace bs
 		if (nearPlane <= 0)
 		{
 			LOGERR("Near clip distance must be greater than zero.");
-            return;
+			return;
 		}
 
 		mNearDist = nearPlane;
@@ -126,8 +126,11 @@ namespace bs
 	ConvexVolume CameraBase::getWorldFrustum() const
 	{
 		const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
+
+		const Transform& tfrm = getTransform();
+
 		Matrix4 worldMatrix;
-		worldMatrix.setTRS(mPosition, mRotation, Vector3::ONE);
+		worldMatrix.setTRS(tfrm.getPosition(), tfrm.getRotation(), Vector3::ONE);
 
 		Vector<Plane> worldPlanes(frustumPlanes.size());
 		UINT32 i = 0;
@@ -324,7 +327,7 @@ namespace bs
 	{
 		if (!mCustomViewMatrix && mRecalcView)
 		{
-			mViewMatrix.makeView(mPosition, mRotation);
+			mViewMatrix.makeView(mTransform.getPosition(), mTransform.getRotation());
 			mViewMatrixInv = mViewMatrix.inverseAffine();
 			mRecalcView = false;
 		}
@@ -461,20 +464,11 @@ namespace bs
 		outbottom = mBottom;
 	}
 
-	void CameraBase::setPosition(const Vector3& position)
+	void CameraBase::setTransform(const Transform& transform)
 	{
-		mPosition = position;
-
+		SceneActor::setTransform(transform);
+		
 		mRecalcView = true;
-		_markCoreDirty(CameraDirtyFlag::Transform);
-	}
-
-	void CameraBase::setRotation(const Quaternion& rotation)
-	{
-		mRotation = rotation;
-
-		mRecalcView = true;
-		_markCoreDirty(CameraDirtyFlag::Transform);
 	}
 
 	void CameraBase::invalidateFrustum() const
@@ -679,7 +673,7 @@ namespace bs
 	}
 
 	Camera::Camera(SPtr<RenderTarget> target, float left, float top, float width, float height)
-		:mMain(false), mLastUpdateHash(0)
+		:mMain(false)
 	{
 		if (target != nullptr)
 			target->blockUntilCoreInitialized();
@@ -720,6 +714,20 @@ namespace bs
 		return handlerPtr;
 	}
 
+	void Camera::initialize()
+	{
+		CoreObject::initialize();
+
+		gSceneManager()._registerCamera(std::static_pointer_cast<Camera>(getThisPtr()));
+	}
+
+	void Camera::destroy()
+	{
+		gSceneManager()._unregisterCamera(std::static_pointer_cast<Camera>(getThisPtr()));
+
+		CoreObject::destroy();
+	}
+
 	Rect2I Camera::getViewportRect() const
 	{
 		return mViewport->getPixelArea();
@@ -729,13 +737,11 @@ namespace bs
 	{
 		UINT32 dirtyFlag = getCoreDirtyFlags();
 
-		UINT32 size = 0;
+		UINT32 size = getActorSyncDataSize();
 		size += rttiGetElemSize(dirtyFlag);
-		size += rttiGetElemSize(mPosition);
-		size += rttiGetElemSize(mRotation);
 
 		UINT32 ppSize = 0;
-		if (dirtyFlag != (UINT32)CameraDirtyFlag::Transform)
+		if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
 		{
 			size += rttiGetElemSize(mLayers);
 			size += rttiGetElemSize(mProjType);
@@ -748,7 +754,6 @@ namespace bs
 			size += rttiGetElemSize(mCustomViewMatrix);
 			size += rttiGetElemSize(mCustomProjMatrix);
 			size += rttiGetElemSize(mFrustumExtentsManuallySet);
-			size += rttiGetElemSize(mIsActive);
 			size += rttiGetElemSize(mMSAA);
 			size += sizeof(UINT32);
 
@@ -762,11 +767,10 @@ namespace bs
 		UINT8* buffer = allocator->alloc(size);
 
 		char* dataPtr = (char*)buffer;
+		dataPtr = syncActorTo(dataPtr);
 		dataPtr = rttiWriteElem(dirtyFlag, dataPtr);
-		dataPtr = rttiWriteElem(mPosition, dataPtr);
-		dataPtr = rttiWriteElem(mRotation, dataPtr);
 
-		if (dirtyFlag != (UINT32)CameraDirtyFlag::Transform)
+		if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
 		{
 			dataPtr = rttiWriteElem(mLayers, dataPtr);
 			dataPtr = rttiWriteElem(mProjType, dataPtr);
@@ -779,7 +783,6 @@ namespace bs
 			dataPtr = rttiWriteElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mFrustumExtentsManuallySet, dataPtr);
-			dataPtr = rttiWriteElem(mIsActive, dataPtr);
 			dataPtr = rttiWriteElem(mMSAA, dataPtr);
 
 			dataPtr = rttiWriteElem(ppSize, dataPtr);
@@ -798,7 +801,7 @@ namespace bs
 		dependencies.push_back(mViewport.get());
 	}
 
-	void Camera::_markCoreDirty(CameraDirtyFlag flag)
+	void Camera::_markCoreDirty(ActorDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);
 	}
@@ -848,16 +851,15 @@ namespace bs
 	{
 		char* dataPtr = (char*)data.getBuffer();
 
-		CameraDirtyFlag dirtyFlag;
+		UINT32 dirtyFlag;
+		dataPtr = syncActorFrom(dataPtr);
 		dataPtr = rttiReadElem(dirtyFlag, dataPtr);
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mRotation, dataPtr);
 
 		mRecalcFrustum = true;
 		mRecalcFrustumPlanes = true;
 		mRecalcView = true;
 
-		if (dirtyFlag != CameraDirtyFlag::Transform)
+		if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
 		{
 			dataPtr = rttiReadElem(mLayers, dataPtr);
 			dataPtr = rttiReadElem(mProjType, dataPtr);
@@ -870,7 +872,6 @@ namespace bs
 			dataPtr = rttiReadElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiReadElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiReadElem(mFrustumExtentsManuallySet, dataPtr);
-			dataPtr = rttiReadElem(mIsActive, dataPtr);
 			dataPtr = rttiReadElem(mMSAA, dataPtr);
 
 			UINT32 ppSize = 0;

+ 18 - 50
Source/BansheeCore/Renderer/BsCamera.h

@@ -14,6 +14,7 @@
 #include "CoreThread/BsCoreObject.h"
 #include "Math/BsConvexVolume.h"
 #include "Renderer/BsRenderSettings.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs 
 {
@@ -24,9 +25,8 @@ namespace bs
 	/**	Signals which portion of a Camera is dirty. */
 	enum class CameraDirtyFlag
 	{
-		Transform = 1<<0,
-		Everything = 1<<1,
-		RenderSettings = 1<<2
+		// First few bits reserved by ActorDiryFlag
+		RenderSettings = 1 << 4
 	};
 
 	/** @} */
@@ -40,11 +40,14 @@ namespace bs
 	 *
 	 * @note	This class contains funcionality common to both core and non-core versions of the camera.
 	 */
-	class BS_CORE_EXPORT CameraBase
+	class BS_CORE_EXPORT CameraBase : public SceneActor
 	{
 	public:
 		virtual ~CameraBase() { }
 
+		/** @copydoc SceneActor::setTransform */
+		void setTransform(const Transform& transform) override;
+
 		/**
 		 * Determines the camera horizontal field of view. This determines how wide the camera viewing angle is along the
 		 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
@@ -78,31 +81,6 @@ namespace bs
 		/** @copydoc setAspectRatio() */
 		virtual float getAspectRatio() const;
 
-		/**	Sets camera world space position. */
-		virtual void setPosition(const Vector3& position);
-
-		/**	Retrieves camera world space position. */
-		virtual Vector3 getPosition() const { return mPosition; }
-
-		/**	Sets should the camera be rendered to or not. */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-		
-		/**	Gets whether the camera be rendered to or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**
-		 * Gets the Z (forward) axis of the object, in world space.
-		 *
-		 * @return	Forward axis of the object.
-		 */
-		Vector3 getForward() const { return getRotation().rotate(-Vector3::UNIT_Z); }
-
-		/**	Sets camera world space rotation. */
-		virtual void setRotation(const Quaternion& rotation);
-
-		/**	Retrieves camera world space rotation. */
-		virtual Quaternion getRotation() const { return mRotation; }
-
 		/** Manually set the extents of the frustum that will be used when calculating the projection matrix. This will
 		 * prevents extents for being automatically calculated from aspect and near plane so it is up to the caller to keep
 		 * these values accurate.
@@ -247,7 +225,8 @@ namespace bs
 		 * Settings that control rendering for this view. They determine how will the renderer process this view, which
 		 * effects will be enabled, and what properties will those effects use.
 		 */
-		void setRenderSettings(const SPtr<RenderSettings>& settings) { mRenderSettings = settings; _markCoreDirty(CameraDirtyFlag::RenderSettings); }
+		void setRenderSettings(const SPtr<RenderSettings>& settings) 
+			{ mRenderSettings = settings; _markCoreDirty((ActorDirtyFlag)CameraDirtyFlag::RenderSettings); }
 
 		/** @copydoc setRenderSettings() */
 		const SPtr<RenderSettings>& getRenderSettings() const { return mRenderSettings; }
@@ -427,19 +406,9 @@ namespace bs
 		/**	Returns a rectangle that defines the viewport position and size, in pixels. */
 		virtual Rect2I getViewportRect() const = 0;
 
-		/** 
-		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
-		 * thread counterpart. 
-		 */
-		virtual void _markCoreDirty(CameraDirtyFlag flag = CameraDirtyFlag::Everything) { }
-
 	protected:
 		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
 
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-		bool mIsActive; /**< Is camera being rendered to. */
-
 		ProjectionType mProjType; /**< Type of camera projection. */
 		Radian mHorzFOV; /**< Horizontal field of view represents how wide is the camera angle. */
 		float mFarDist; /**< Clip any objects further than this. Larger value decreases depth precision at smaller depths. */
@@ -500,18 +469,18 @@ namespace bs
 		static SPtr<Camera> create(SPtr<RenderTarget> target = nullptr,
 			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
 
-		/** @name Internal
-		 *  @{
+		/** 
+		 * @name Internal
+		 * @{
 		 */
 
-		/**	Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
+		/** @copydoc CoreObject::initialize */
+		void initialize() override;
 
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
+		/** @copydoc CoreObject::destroy */
+		void destroy() override;
 
 		/** @} */
-
 	protected:
 		Camera(SPtr<RenderTarget> target = nullptr,
 			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
@@ -523,7 +492,7 @@ namespace bs
 		SPtr<ct::CoreObject> createCore() const override;
 
 		/** @copydoc CameraBase::_markCoreDirty */
-		void _markCoreDirty(CameraDirtyFlag flag = CameraDirtyFlag::Everything) override;
+		void _markCoreDirty(ActorDirtyFlag flag = ActorDirtyFlag::Everything) override;
 
 		/** @copydoc CoreObject::syncToCore */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
@@ -536,7 +505,6 @@ namespace bs
 
 		SPtr<Viewport> mViewport; /**< Viewport that describes 2D rendering surface. */
 		bool mMain;
-		UINT32 mLastUpdateHash;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -587,4 +555,4 @@ namespace bs
 	}
 
 	/** @} */
-}
+}

+ 21 - 51
Source/BansheeCore/Renderer/BsLight.cpp

@@ -10,18 +10,16 @@
 namespace bs
 {
 	LightBase::LightBase()
-		: mPosition(BsZero), mRotation(BsIdentity), mType(LightType::Radial), mCastsShadows(false), mColor(Color::White)
-		, mAttRadius(10.0f), mSourceRadius(0.0f), mIntensity(5.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f)
-		, mIsActive(true), mAutoAttenuation(true), mMobility(ObjectMobility::Movable), mShadowBias(0.5f)
+		: mType(LightType::Radial), mCastsShadows(false), mColor(Color::White), mAttRadius(10.0f), mSourceRadius(0.0f)
+		, mIntensity(5.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f), mAutoAttenuation(true), mShadowBias(0.5f)
 	{
 		updateAttenuationRange();
 	}
 
 	LightBase::LightBase(LightType type, Color color, float intensity, float attRadius, float srcRadius, bool castsShadows, 
 		Degree spotAngle, Degree spotFalloffAngle)
-		: mPosition(BsZero), mRotation(BsIdentity), mType(type), mCastsShadows(castsShadows), mColor(color)
-		, mAttRadius(attRadius), mSourceRadius(srcRadius), mIntensity(intensity), mSpotAngle(spotAngle)
-		, mSpotFalloffAngle(spotFalloffAngle), mIsActive(true), mAutoAttenuation(true), mMobility(ObjectMobility::Movable)
+		: mType(type), mCastsShadows(castsShadows), mColor(color), mAttRadius(attRadius), mSourceRadius(srcRadius)
+		, mIntensity(intensity), mSpotAngle(spotAngle), mSpotFalloffAngle(spotFalloffAngle), mAutoAttenuation(true)
 		, mShadowBias(0.5f)
 	{
 		updateAttenuationRange();
@@ -136,13 +134,15 @@ namespace bs
 
 	void LightBase::updateBounds()
 	{
+		const Transform& tfrm = getTransform();
+
 		switch (mType)
 		{
 		case LightType::Directional:
-			mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
+			mBounds = Sphere(tfrm.getPosition(), std::numeric_limits<float>::infinity());
 			break;
 		case LightType::Radial:
-			mBounds = Sphere(mPosition, mAttRadius);
+			mBounds = Sphere(tfrm.getPosition(), mAttRadius);
 			break;
 		case LightType::Spot:
 		{
@@ -159,7 +159,7 @@ namespace bs
 			// the middle of the range)
 			float radius = (offset - coneDir).length();
 
-			Vector3 center = mPosition + mRotation.rotate(offset);
+			Vector3 center = tfrm.getPosition() + tfrm.getRotation().rotate(offset);
 			mBounds = Sphere(center, radius);
 		}
 			break;
@@ -168,23 +168,14 @@ namespace bs
 		}
 	}
 
-	void LightBase::setMobility(ObjectMobility mobility)
-	{
-		mMobility = mobility;
-
-		_markCoreDirty(LightDirtyFlag::Mobility);
-	}
-
 	Light::Light()
-		:mLastUpdateHash(0)
 	{
 		
 	}
 
 	Light::Light(LightType type, Color color, float intensity, float attRadius, float srcRadius, bool castsShadows, 
 		Degree spotAngle, Degree spotFalloffAngle)
-		: LightBase(type, color, intensity, attRadius, srcRadius, castsShadows, spotAngle, spotFalloffAngle),
-		mLastUpdateHash(0)
+		: LightBase(type, color, intensity, attRadius, srcRadius, castsShadows, spotAngle, spotFalloffAngle)
 	{
 		// Calling virtual method is okay here because this is the most derived type
 		updateBounds();
@@ -228,9 +219,7 @@ namespace bs
 
 	CoreSyncData Light::syncToCore(FrameAlloc* allocator)
 	{
-		UINT32 size = 0;
-		size += rttiGetElemSize(mPosition);
-		size += rttiGetElemSize(mRotation);
+		UINT32 size = getActorSyncDataSize();
 		size += rttiGetElemSize(mType);
 		size += rttiGetElemSize(mCastsShadows);
 		size += rttiGetElemSize(mColor);
@@ -240,17 +229,14 @@ namespace bs
 		size += rttiGetElemSize(mSpotAngle);
 		size += rttiGetElemSize(mSpotFalloffAngle);
 		size += rttiGetElemSize(mAutoAttenuation);
-		size += rttiGetElemSize(mIsActive);
 		size += rttiGetElemSize(getCoreDirtyFlags());
 		size += rttiGetElemSize(mBounds);
-		size += rttiGetElemSize(mMobility);
 		size += rttiGetElemSize(mShadowBias);
 
 		UINT8* buffer = allocator->alloc(size);
 
 		char* dataPtr = (char*)buffer;
-		dataPtr = rttiWriteElem(mPosition, dataPtr);
-		dataPtr = rttiWriteElem(mRotation, dataPtr);
+		dataPtr = syncActorTo(dataPtr);
 		dataPtr = rttiWriteElem(mType, dataPtr);
 		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
 		dataPtr = rttiWriteElem(mColor, dataPtr);
@@ -260,27 +246,14 @@ namespace bs
 		dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
 		dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
 		dataPtr = rttiWriteElem(mAutoAttenuation, dataPtr);
-		dataPtr = rttiWriteElem(mIsActive, dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 		dataPtr = rttiWriteElem(mBounds, dataPtr);
-		dataPtr = rttiWriteElem(mMobility, dataPtr);
 		dataPtr = rttiWriteElem(mShadowBias, dataPtr);
 
 		return CoreSyncData(buffer, size);
 	}
 
-	void Light::_updateTransform(const HSceneObject& parent)
-	{
-		UINT32 curHash = parent->getTransformHash();
-		if (curHash != _getLastModifiedHash())
-		{
-			setPosition(parent->getWorldPosition());
-			setRotation(parent->getWorldRotation());
-			_setLastModifiedHash(curHash);
-		}
-	}
-
-	void Light::_markCoreDirty(LightDirtyFlag flag)
+	void Light::_markCoreDirty(ActorDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);
 	}
@@ -325,11 +298,10 @@ namespace bs
 		char* dataPtr = (char*)data.getBuffer();
 
 		UINT32 dirtyFlags = 0;
-		bool oldIsActive = mIsActive;
+		bool oldIsActive = mActive;
 		LightType oldType = mType;
 
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mRotation, dataPtr);
+		dataPtr = syncActorFrom(dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
 		dataPtr = rttiReadElem(mColor, dataPtr);
@@ -339,19 +311,17 @@ namespace bs
 		dataPtr = rttiReadElem(mSpotAngle, dataPtr);
 		dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
 		dataPtr = rttiReadElem(mAutoAttenuation, dataPtr);
-		dataPtr = rttiReadElem(mIsActive, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 		dataPtr = rttiReadElem(mBounds, dataPtr);
-		dataPtr = rttiReadElem(mMobility, dataPtr);
 		dataPtr = rttiReadElem(mShadowBias, dataPtr);
 
 		updateBounds();
 
-		if((dirtyFlags & (UINT32)LightDirtyFlag::Everything) != 0)
+		if((dirtyFlags & ((UINT32)ActorDirtyFlag::Everything | (UINT32)ActorDirtyFlag::Active)) != 0)
 		{
-			if (oldIsActive != mIsActive)
+			if (oldIsActive != mActive)
 			{
-				if (mIsActive)
+				if (mActive)
 					gRenderer()->notifyLightAdded(this);
 				else
 				{
@@ -371,14 +341,14 @@ namespace bs
 				gRenderer()->notifyLightAdded(this);
 			}
 		}
-		else if((dirtyFlags & (UINT32)LightDirtyFlag::Mobility) != 0)
+		else if((dirtyFlags & (UINT32)ActorDirtyFlag::Mobility) != 0)
 		{
 			gRenderer()->notifyLightRemoved(this);
 			gRenderer()->notifyLightAdded(this);
 		}
-		else if ((dirtyFlags & (UINT32)LightDirtyFlag::Transform) != 0)
+		else if ((dirtyFlags & (UINT32)ActorDirtyFlag::Transform) != 0)
 		{
-			if (mIsActive)
+			if (mActive)
 				gRenderer()->notifyLightUpdated(this);
 		}
 	}

+ 4 - 71
Source/BansheeCore/Renderer/BsLight.h

@@ -9,6 +9,7 @@
 #include "Image/BsColor.h"
 #include "Math/BsSphere.h"
 #include "CoreThread/BsCoreObject.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs
 {
@@ -26,14 +27,6 @@ namespace bs
 		Count			BS_SCRIPT_EXPORT(ex:true) // Keep at end
 	};
 
-	/**	Signals which portion of a light is dirty. */
-	enum class LightDirtyFlag
-	{
-		Transform = 0x01,
-		Everything = 0x02,
-		Mobility = 0x04
-	};
-
 	/** @} */
 
 	/** @addtogroup Implementation
@@ -41,7 +34,7 @@ namespace bs
 	 */
 
 	/** Base class for both sim and core thread Light implementations. */
-	class BS_CORE_EXPORT LightBase
+	class BS_CORE_EXPORT LightBase : public SceneActor
 	{
 	public:
 		LightBase();
@@ -50,20 +43,6 @@ namespace bs
 
 		virtual ~LightBase() { }
 
-		/**	Returns the position of the light, in world space. */
-		Vector3 getPosition() const { return mPosition; }
-
-		/**	Sets the position of the light, in world space. */
-		void setPosition(const Vector3& position) 
-			{ mPosition = position; _markCoreDirty(LightDirtyFlag::Transform); updateBounds(); }
-
-		/**	Returns the rotation of the light, in world space. */
-		Quaternion getRotation() const { return mRotation; }
-
-		/**	Sets the rotation of the light, in world space. */
-		void setRotation(const Quaternion& rotation) 
-			{ mRotation = rotation; _markCoreDirty(LightDirtyFlag::Transform); updateBounds(); }
-
 		/**	Determines the type of the light. */
 		LightType getType() const { return mType; }
 
@@ -167,31 +146,6 @@ namespace bs
 		 */
 		float getLuminance() const;
 
-		/**	Checks whether the light should be rendered or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**	Sets whether the light should be rendered or not. */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-
-		/**
-		 * Sets the mobility of a scene object. This is used primarily as a performance hint to engine systems. Objects
-		 * with more restricted mobility will result in higher performance. Some mobility constraints will be enforced by
-		 * the engine itself, while for others the caller must be sure not to break the promise he made when mobility was
-		 * set. By default scene object's mobility is unrestricted.
-		 */
-		void setMobility(ObjectMobility mobility);
-
-		/** 
-		 * Gets the mobility setting for this scene object. See setMobility(); 
-		 */
-		ObjectMobility getMobility() const { return mMobility; }
-
-		/** 
-		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
-		 * thread counterpart. 
-		 */
-		virtual void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) { }
-
 	protected:
 		/** Updates the internal bounds for the light. Call this whenever a property affecting the bounds changes. */
 		void updateBounds();
@@ -199,9 +153,6 @@ namespace bs
 		/** Calculates maximum light range based on light intensity. */
 		void updateAttenuationRange();
 
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-
 		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
 		bool mCastsShadows; /**< Determines whether the light casts shadows. */
 		Color mColor; /**< Color of the light. */
@@ -210,10 +161,8 @@ namespace bs
 		float mIntensity; /**< Power of the light source. @see setIntensity. */
 		Degree mSpotAngle; /**< Total angle covered by a spot light. */
 		Degree mSpotFalloffAngle; /**< Spot light angle at which falloff starts. Must be smaller than total angle. */
-		bool mIsActive; /**< Whether the light should be rendered or not. */
 		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
 		bool mAutoAttenuation; /**< Determines is attenuation radius is automatically determined. */
-		ObjectMobility mMobility; /**< Determines if there are any restrictions placed on light movement. */
 		float mShadowBias; /**< See setShadowBias() */
 	};
 
@@ -231,20 +180,6 @@ namespace bs
 		/**	Retrieves an implementation of the light usable only from the core thread. */
 		SPtr<ct::Light> getCore() const;
 
-		/** Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/**
-		 * Updates internal transform values from the specified scene object, in case that scene object's transform changed
-		 * since the last call.
-		 *
-		 * @note	Assumes the same scene object will be provided every time.
-		 */
-		void _updateTransform(const HSceneObject& parent);
-
 		/**
 		 * Creates a new light with provided settings.
 		 *
@@ -270,7 +205,7 @@ namespace bs
 		SPtr<ct::CoreObject> createCore() const override;
 
 		/** @copydoc LightBase::_markCoreDirty */
-		void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) override;
+		void _markCoreDirty(ActorDirtyFlag flag = ActorDirtyFlag::Everything) override;
 
 		/** @copydoc CoreObject::syncToCore */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
@@ -278,8 +213,6 @@ namespace bs
 		/**	Creates a light with without initializing it. Used for serialization. */
 		static SPtr<Light> createEmpty();
 
-		UINT32 mLastUpdateHash;
-
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
@@ -325,4 +258,4 @@ namespace bs
 	}
 
 	/** @} */
-}
+}

+ 15 - 34
Source/BansheeCore/Renderer/BsLightProbeVolume.cpp

@@ -12,16 +12,12 @@
 
 namespace bs
 {
-	LightProbeVolumeBase::LightProbeVolumeBase()
-		: mPosition(BsZero), mRotation(BsIdentity), mIsActive(true)
-	{ }
-
 	LightProbeVolume::LightProbeVolume()
-		: mVolume(AABox::UNIT_BOX), mCellCount { 1, 1, 1 }, mLastUpdateHash(0)
+		: mVolume(AABox::UNIT_BOX), mCellCount { 1, 1, 1 }
 	{ }
 
 	LightProbeVolume::LightProbeVolume(const AABox& volume, const Vector3I& cellCount)
-		:mVolume(volume), mCellCount(cellCount), mLastUpdateHash(0)
+		:mVolume(volume), mCellCount(cellCount)
 	{
 		reset();
 	}
@@ -217,19 +213,6 @@ namespace bs
 		}
 	}
 
-	void LightProbeVolume::_updateTransform(const HSceneObject& so, bool force)
-	{
-		UINT32 curHash = so->getTransformHash();
-		if (curHash != _getLastModifiedHash() || force)
-		{
-			mPosition = so->getWorldPosition();
-			mRotation = so->getWorldRotation();
-
-			_markCoreDirty();
-			_setLastModifiedHash(curHash);
-		}
-	}
-
 	void LightProbeVolume::runRenderProbeTask()
 	{
 		// If a task is already running cancel it
@@ -346,9 +329,7 @@ namespace bs
 			UINT32 numDirtyProbes = (UINT32)dirtyProbes.size();
 			UINT32 numRemovedProbes = (UINT32)removedProbes.size();
 
-			size += rttiGetElemSize(mPosition);
-			size += rttiGetElemSize(mRotation);
-			size += rttiGetElemSize(mIsActive);
+			size += getActorSyncDataSize();
 			size += rttiGetElemSize(numDirtyProbes);
 			size += rttiGetElemSize(numRemovedProbes);
 			size += (sizeof(UINT32) + sizeof(Vector3) + sizeof(LightProbeFlags)) * numDirtyProbes;
@@ -357,9 +338,7 @@ namespace bs
 			buffer = allocator->alloc(size);
 
 			char* dataPtr = (char*)buffer;
-			dataPtr = rttiWriteElem(mPosition, dataPtr);
-			dataPtr = rttiWriteElem(mRotation, dataPtr);
-			dataPtr = rttiWriteElem(mIsActive, dataPtr);
+			dataPtr = syncActorTo(dataPtr);
 			dataPtr = rttiWriteElem(numDirtyProbes, dataPtr);
 			dataPtr = rttiWriteElem(numRemovedProbes, dataPtr);
 
@@ -378,9 +357,9 @@ namespace bs
 		return CoreSyncData(buffer, size);
 	}
 
-	void LightProbeVolume::_markCoreDirty()
+	void LightProbeVolume::_markCoreDirty(ActorDirtyFlag dirtyFlag)
 	{
-		markCoreDirty();
+		markCoreDirty((UINT32)dirtyFlag);
 	}
 
 	RTTITypeBase* LightProbeVolume::getRTTIStatic()
@@ -462,7 +441,11 @@ namespace bs
 				SPtr<Texture> cubemap = Texture::create(cubemapDesc);
 
 				Vector3 localPos = mProbePositions[mFirstDirtyProbe];
-				Vector3 transformedPos = mRotation.rotate(localPos) + mPosition;
+
+				const Transform& tfrm = getTransform();
+				const Vector3& position = tfrm.getPosition();
+				const Quaternion& rotation = tfrm.getRotation();
+				Vector3 transformedPos = rotation.rotate(localPos) + position;
 
 				gRenderer()->captureSceneCubeMap(cubemap, transformedPos, CaptureSettings());
 				gIBLUtility().filterCubemapForIrradiance(cubemap, mCoefficients, probeInfo.bufferIdx);
@@ -484,11 +467,9 @@ namespace bs
 	{
 		char* dataPtr = (char*)data.getBuffer();
 
-		bool oldIsActive = mIsActive;
+		bool oldIsActive = mActive;
 
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mRotation, dataPtr);
-		dataPtr = rttiReadElem(mIsActive, dataPtr);
+		dataPtr = syncActorFrom(dataPtr);
 
 		UINT32 numDirtyProbes, numRemovedProbes;
 		dataPtr = rttiReadElem(numDirtyProbes, dataPtr);
@@ -596,9 +577,9 @@ namespace bs
 			}
 		}
 
-		if (oldIsActive != mIsActive)
+		if (oldIsActive != mActive)
 		{
-			if (mIsActive)
+			if (mActive)
 				gRenderer()->notifyLightProbeVolumeAdded(this);
 			else
 				gRenderer()->notifyLightProbeVolumeRemoved(this);

+ 6 - 51
Source/BansheeCore/Renderer/BsLightProbeVolume.h

@@ -8,6 +8,7 @@
 #include "Math/BsVector3.h"
 #include "Math/BsQuaternion.h"
 #include "Math/BsVectorNI.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs
 {
@@ -26,44 +27,8 @@ namespace bs
 		 Empty, Clean, Dirty, Removed 
 	};
 
-	/** Base class for both sim and core thread LightProbeVolume implementations. */
-	class BS_CORE_EXPORT LightProbeVolumeBase
-	{
-	public:
-		LightProbeVolumeBase();
-		virtual ~LightProbeVolumeBase() { }
-
-		/**	Returns the position of the volume, in world space. */
-		Vector3 getPosition() const { return mPosition; }
-
-		/**	Sets the position of the volume, in world space. */
-		void setPosition(const Vector3& position) { mPosition = position; _markCoreDirty(); }
-
-		/**	Returns the rotation of the volume, in world space. */
-		Quaternion getRotation() const { return mRotation; }
-
-		/**	Sets the rotation of the light, in world space. */
-		void setRotation(const Quaternion& rotation) { mRotation = rotation; _markCoreDirty(); }
-
-		/**	Checks whether the light volume should be used during rendering or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**	Sets whether the light volume should be used during rendering or not. */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-
-		/** 
-		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
-		 * thread counterpart. 
-		 */
-		virtual void _markCoreDirty() { }
-
-	protected:
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-		bool mIsActive; /**< Whether the light volume should be used during rendering or not. */
-	};
-
 	/** @} */
+
 	/** @addtogroup Renderer-Internal
 	 *  @{
 	 */
@@ -104,7 +69,7 @@ namespace bs
 	 *
 	 * The volume can never have less than 4 probes.
 	 */
-	class BS_CORE_EXPORT LightProbeVolume : public IReflectable, public CoreObject, public LightProbeVolumeBase
+	class BS_CORE_EXPORT LightProbeVolume : public IReflectable, public CoreObject, public SceneActor
 	{
 		/** Internal information about a single light probe. */
 		struct ProbeInfo
@@ -191,15 +156,6 @@ namespace bs
 		 *							volume in an uniform way.
 		 */
 		static SPtr<LightProbeVolume> create(const AABox& volume = AABox::UNIT_BOX, const Vector3I& cellCount = {1, 1, 1});
-
-		/**	Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/** Updates the transfrom from the provided scene object, if the scene object's data is detected to be dirty. */
-		void _updateTransform(const HSceneObject& so, bool force = false);
 	protected:
 		friend class ct::LightProbeVolume;
 
@@ -217,8 +173,8 @@ namespace bs
 		/** @copydoc CoreObject::createCore */
 		SPtr<ct::CoreObject> createCore() const override;
 
-		/** @copydoc LightProbeVolumeBase::_markCoreDirty */
-		void _markCoreDirty() override;
+		/** @copydoc SceneActor::_markCoreDirty */
+		void _markCoreDirty(ActorDirtyFlag dirtFlags = ActorDirtyFlag::Everything) override;
 
 		/** @copydoc CoreObject::syncToCore */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
@@ -230,7 +186,6 @@ namespace bs
 		UnorderedMap<UINT32, ProbeInfo> mProbes;
 		AABox mVolume = AABox::UNIT_BOX;
 		Vector3I mCellCount;
-		UINT32 mLastUpdateHash;
 
 		UINT32 mNextProbeId = 0;
 		SPtr<ct::RendererTask> mRendererTask;
@@ -263,7 +218,7 @@ namespace bs
 	};
 
 	/** Core thread usable version of bs::LightProbeVolume. */
-	class BS_CORE_EXPORT LightProbeVolume : public CoreObject, public LightProbeVolumeBase
+	class BS_CORE_EXPORT LightProbeVolume : public CoreObject, public SceneActor
 	{
 	public:
 		~LightProbeVolume();

+ 25 - 41
Source/BansheeCore/Renderer/BsReflectionProbe.cpp

@@ -12,36 +12,43 @@
 namespace bs
 {
 	ReflectionProbeBase::ReflectionProbeBase()
-		: mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(ReflectionProbeType::Box), mRadius(1.0f)
-		, mExtents(1.0f, 1.0f, 1.0f), mTransitionDistance(0.1f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
+		: mType(ReflectionProbeType::Box), mRadius(1.0f), mExtents(1.0f, 1.0f, 1.0f), mTransitionDistance(0.1f)
+		, mBounds(Vector3::ZERO, 1.0f)
 	{ }
 
 	ReflectionProbeBase::ReflectionProbeBase(ReflectionProbeType type, float radius, const Vector3& extents)
-		: mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(type), mRadius(radius)
-		, mExtents(extents), mTransitionDistance(0.1f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
+		: mType(type), mRadius(radius), mExtents(extents), mTransitionDistance(0.1f), mBounds(Vector3::ZERO, 1.0f)
 	{ }
 
+	float ReflectionProbeBase::getRadius() const
+	{
+		Vector3 scale = mTransform.getScale();
+		return mRadius * std::max(std::max(scale.x, scale.y), scale.z);
+	}
+
 	void ReflectionProbeBase::updateBounds()
 	{
+		Vector3 position = mTransform.getPosition();
+		Vector3 scale = mTransform.getScale();
+
 		switch (mType)
 		{
 		case ReflectionProbeType::Sphere:
-			mBounds = Sphere(mPosition, mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z));
+			mBounds = Sphere(position, mRadius * std::max(std::max(scale.x, scale.y), scale.z));
 			break;
 		case ReflectionProbeType::Box:
-			mBounds = Sphere(mPosition, (mExtents * mScale).length());
+			mBounds = Sphere(position, (mExtents * scale).length());
 			break;
 		}
 	}
 
 	ReflectionProbe::ReflectionProbe()
-		:mLastUpdateHash(0)
 	{
 
 	}
 
 	ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
-		: ReflectionProbeBase(type, radius, extents), mLastUpdateHash(0)
+		: ReflectionProbeBase(type, radius, extents)
 	{
 		// Calling virtual method is okay here because this is the most derived type
 		updateBounds();
@@ -105,7 +112,7 @@ namespace bs
 				settings.depthEncodeNear = radius;
 				settings.depthEncodeFar = radius + 1; // + 1 arbitrary, make it a customizable value?
 
-				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), settings);
+				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getTransform().getPosition(), settings);
 				ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
 
 				coreProbe->mFilteredTexture = coreTexture;
@@ -190,15 +197,11 @@ namespace bs
 
 	CoreSyncData ReflectionProbe::syncToCore(FrameAlloc* allocator)
 	{
-		UINT32 size = 0;
-		size += rttiGetElemSize(mPosition);
-		size += rttiGetElemSize(mRotation);
-		size += rttiGetElemSize(mScale);
+		UINT32 size = getActorSyncDataSize();
 		size += rttiGetElemSize(mType);
 		size += rttiGetElemSize(mRadius);
 		size += rttiGetElemSize(mExtents);
 		size += rttiGetElemSize(mTransitionDistance);
-		size += rttiGetElemSize(mIsActive);
 		size += rttiGetElemSize(getCoreDirtyFlags());
 		size += rttiGetElemSize(mBounds);
 		size += sizeof(SPtr<ct::Texture>);
@@ -207,14 +210,11 @@ namespace bs
 		UINT8* buffer = allocator->alloc(size);
 
 		char* dataPtr = (char*)buffer;
-		dataPtr = rttiWriteElem(mPosition, dataPtr);
-		dataPtr = rttiWriteElem(mRotation, dataPtr);
-		dataPtr = rttiWriteElem(mScale, dataPtr);
+		dataPtr = syncActorTo(dataPtr);
 		dataPtr = rttiWriteElem(mType, dataPtr);
 		dataPtr = rttiWriteElem(mRadius, dataPtr);
 		dataPtr = rttiWriteElem(mExtents, dataPtr);
 		dataPtr = rttiWriteElem(mTransitionDistance, dataPtr);
-		dataPtr = rttiWriteElem(mIsActive, dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 		dataPtr = rttiWriteElem(mBounds, dataPtr);
 		dataPtr = rttiWriteElem(mUUID, dataPtr);
@@ -222,20 +222,7 @@ namespace bs
 		return CoreSyncData(buffer, size);
 	}
 
-	void ReflectionProbe::_updateTransform(const HSceneObject& parent)
-	{
-		UINT32 curHash = parent->getTransformHash();
-		if (curHash != _getLastModifiedHash())
-		{
-			setPosition(parent->getWorldPosition());
-			setRotation(parent->getWorldRotation());
-			setScale(parent->getWorldScale());
-
-			_setLastModifiedHash(curHash);
-		}
-	}
-
-	void ReflectionProbe::_markCoreDirty(ReflectionProbeDirtyFlag flags)
+	void ReflectionProbe::_markCoreDirty(ActorDirtyFlag flags)
 	{
 		markCoreDirty((UINT32)flags);
 	}
@@ -277,33 +264,30 @@ namespace bs
 		char* dataPtr = (char*)data.getBuffer();
 
 		UINT32 dirtyFlags = 0;
-		bool oldIsActive = mIsActive;
+		bool oldIsActive = mActive;
 		ReflectionProbeType oldType = mType;
 
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mRotation, dataPtr);
-		dataPtr = rttiReadElem(mScale, dataPtr);
+		dataPtr = syncActorFrom(dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mRadius, dataPtr);
 		dataPtr = rttiReadElem(mExtents, dataPtr);
 		dataPtr = rttiReadElem(mTransitionDistance, dataPtr);
-		dataPtr = rttiReadElem(mIsActive, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 		dataPtr = rttiReadElem(mBounds, dataPtr);
 		dataPtr = rttiReadElem(mUUID, dataPtr);
 
 		updateBounds();
 
-		if (dirtyFlags == (UINT32)ReflectionProbeDirtyFlag::Transform)
+		if (dirtyFlags == (UINT32)ActorDirtyFlag::Transform)
 		{
-			if (mIsActive)
+			if (mActive)
 				gRenderer()->notifyReflectionProbeUpdated(this, false);
 		}
 		else
 		{
-			if (oldIsActive != mIsActive)
+			if (oldIsActive != mActive)
 			{
-				if (mIsActive)
+				if (mActive)
 					gRenderer()->notifyReflectionProbeAdded(this);
 				else
 				{

+ 6 - 65
Source/BansheeCore/Renderer/BsReflectionProbe.h

@@ -8,6 +8,7 @@
 #include "Math/BsVector3.h"
 #include "Math/BsQuaternion.h"
 #include "Math/BsSphere.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs
 {
@@ -30,13 +31,6 @@ namespace bs
 		Sphere
 	};
 
-	/**	Signals which portion of a reflection probe is dirty. */
-	enum class ReflectionProbeDirtyFlag
-	{
-		Transform = 0x01,
-		Everything = 0x02
-	};
-
 	/** @} */
 
 	/** @addtogroup Implementation
@@ -44,34 +38,13 @@ namespace bs
 	 */
 
 	/** Base class for both core and sim thread implementations of a reflection probe. */
-	class BS_CORE_EXPORT ReflectionProbeBase
+	class BS_CORE_EXPORT ReflectionProbeBase : public SceneActor
 	{
 	public:
 		ReflectionProbeBase();
 		ReflectionProbeBase(ReflectionProbeType type, float radius, const Vector3& extents);
 		virtual ~ReflectionProbeBase() { }
 
-		/**	Returns the position of the probe, in world space. */
-		Vector3 getPosition() const { return mPosition; }
-
-		/**	Sets the position of the probe, in world space. */
-		void setPosition(const Vector3& position) 
-			{ mPosition = position; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
-
-		/**	Returns the rotation of the probe, in world space. */
-		Quaternion getRotation() const { return mRotation; }
-
-		/**	Sets the rotation of the probe, in world space. */
-		void setRotation(const Quaternion& rotation) 
-			{ mRotation = rotation; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
-
-		/**	Returns the scale of the probe. */
-		Vector3 getScale() const { return mScale; }
-
-		/**	Sets the scale of the probe. */
-		void setScale(const Vector3& scale)
-			{ mScale = scale; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
-
 		/**	Returns the type of the probe. */
 		ReflectionProbeType getType() const { return mType; }
 
@@ -79,13 +52,13 @@ namespace bs
 		void setType(ReflectionProbeType type) { mType = type; _markCoreDirty(); updateBounds(); }
 
 		/** Returns the radius of a sphere reflection probe. Determines range of influence. */
-		float getRadius() const { return mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z); }
+		float getRadius() const;
 
 		/** Sets the radius of a sphere reflection probe. */
 		void setRadius(float radius) { mRadius = radius; _markCoreDirty(); updateBounds(); }
 
 		/** Returns the extents of a box reflection probe. */
-		Vector3 getExtents() const { return mExtents * mScale; }
+		Vector3 getExtents() const { return mExtents * mTransform.getScale(); }
 
 		/** Sets the extents of a box reflection probe. Determines range of influence. */
 		void setExtents(const Vector3& extents) { mExtents = extents; _markCoreDirty(); updateBounds(); }
@@ -102,36 +75,19 @@ namespace bs
 		/** Retrieves transition distance set by setTransitionDistance(). */
 		float getTransitionDistance() const { return mTransitionDistance; }
 
-		/**	Checks whether the probe should be used or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**	Sets whether the probe should be used or not. */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-
 		/** Returns an identifier that uniquely identifies the probe. */
 		const String& getUUID() const { return mUUID; }
 
-		/** 
-		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
-		 * thread counterpart. 
-		 */
-		virtual void _markCoreDirty(ReflectionProbeDirtyFlag flags = ReflectionProbeDirtyFlag::Everything) { }
-
 	protected:
 		/** Updates the internal bounds for the probe. Call this whenever a property affecting the bounds changes. */
 		void updateBounds();
 
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-		Vector3 mScale; /** Scale applied to radius/extents. */
-
 		ReflectionProbeType mType; /**< Type of probe that determines how are the rest of the parameters interpreted. */
 		float mRadius; /**< Radius used for sphere reflection probes. */
 		Vector3 mExtents; /**< Extents used by box reflection probe. */
 		float mTransitionDistance; /**< Extra distance to used for fading out box probes. */
 		String mUUID; /**< Identifier that uniquely identifies the probe. */
 
-		bool mIsActive; /**< Whether the light should be rendered or not. */
 		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
 	};
 
@@ -184,20 +140,6 @@ namespace bs
 		/**	Retrieves an implementation of the reflection probe usable only from the core thread. */
 		SPtr<ct::ReflectionProbe> getCore() const;
 
-		/** Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/**
-		 * Updates internal transform values from the specified scene object, in case that scene object's transform changed
-		 * since the last call.
-		 *
-		 * @note	Assumes the same scene object will be provided every time.
-		 */
-		void _updateTransform(const HSceneObject& parent);
-
 		/**
 		 * Creates a new sphere reflection probe.
 		 *
@@ -221,7 +163,7 @@ namespace bs
 		SPtr<ct::CoreObject> createCore() const override;
 
 		/** @copydoc ReflectionProbeBase::_markCoreDirty */
-		void _markCoreDirty(ReflectionProbeDirtyFlag flags = ReflectionProbeDirtyFlag::Everything) override;
+		void _markCoreDirty(ActorDirtyFlag flags = ActorDirtyFlag::Everything) override;
 
 		/** @copydoc CoreObject::syncToCore */
 		CoreSyncData syncToCore(FrameAlloc* allocator) override;
@@ -235,7 +177,6 @@ namespace bs
 		/**	Creates a light with without initializing it. Used for serialization. */
 		static SPtr<ReflectionProbe> createEmpty();
 
-		UINT32 mLastUpdateHash;
 		HTexture mCustomTexture;
 
 		SPtr<ct::RendererTask> mRendererTask;
@@ -289,4 +230,4 @@ namespace bs
 	}
 
 	/** @} */
-}
+}

+ 62 - 84
Source/BansheeCore/Renderer/BsRenderable.cpp

@@ -12,6 +12,7 @@
 #include "Animation/BsMorphShapes.h"
 #include "RenderAPI/BsGpuBuffer.h"
 #include "Animation/BsAnimationManager.h"
+#include "Scene/BsSceneManager.h"
 
 namespace bs
 {
@@ -26,8 +27,8 @@ namespace bs
 
 	template<bool Core>
 	TRenderable<Core>::TRenderable()
-		: mLayer(1), mUseOverrideBounds(false), mPosition(BsZero), mTransform(BsIdentity), mTransformNoScale(BsIdentity)
-		, mIsActive(true), mAnimType(RenderableAnimType::None), mMobility(ObjectMobility::Movable)
+		: mLayer(1), mUseOverrideBounds(false), mTfrmMatrix(BsIdentity), mTfrmMatrixNoScale(BsIdentity)
+		, mAnimType(RenderableAnimType::None)
 	{
 		mMaterials.resize(1);
 	}
@@ -38,6 +39,19 @@ namespace bs
 
 	}
 
+	template <bool Core>
+	void TRenderable<Core>::setTransform(const Transform& transform)
+	{
+		if (mMobility != ObjectMobility::Movable)
+			return;
+
+		mTransform = transform;
+		mTfrmMatrix = transform.getMatrix();
+		mTfrmMatrixNoScale = Matrix4::TRS(transform.getPosition(), transform.getRotation(), Vector3::ONE);
+
+		_markCoreDirty(ActorDirtyFlag::Transform);
+	}
+
 	template<bool Core>
 	void TRenderable<Core>::setMesh(const MeshType& mesh)
 	{
@@ -105,33 +119,8 @@ namespace bs
 
 		mLayer = layer;
 		_markCoreDirty();
-	}
-
-	template<bool Core>
-	void TRenderable<Core>::setTransform(const Matrix4& transform, const Matrix4& transformNoScale)
-	{
-		mTransform = transform;
-		mTransformNoScale = transformNoScale;
-		mPosition = mTransform.getTranslation();
-
-		_markCoreDirty(RenderableDirtyFlag::Transform);
-	}
-
-	template<bool Core>
-	void TRenderable<Core>::setIsActive(bool active)
-	{
-		mIsActive = active;
-		_markCoreDirty();
-	}
-
-	template <bool Core>
-	void TRenderable<Core>::setMobility(ObjectMobility mobility)
-	{
-		mMobility = mobility;
-
-		_markCoreDirty(RenderableDirtyFlag::Mobility);
-	}
-
+	}	
+	
 	template<bool Core>
 	void TRenderable<Core>::setOverrideBounds(const AABox& bounds)
 	{
@@ -154,12 +143,6 @@ namespace bs
 	template class TRenderable < false >;
 	template class TRenderable < true >;
 
-	Renderable::Renderable()
-		:mLastUpdateHash(0)
-	{
-		
-	}
-
 	void Renderable::setAnimation(const SPtr<Animation>& animation)
 	{
 		mAnimation = animation;
@@ -175,7 +158,7 @@ namespace bs
 			Sphere sphere(mOverrideBounds.getCenter(), mOverrideBounds.getRadius());
 
 			Bounds bounds(mOverrideBounds, sphere);
-			bounds.transformAffine(mTransform);
+			bounds.transformAffine(mTfrmMatrix);
 
 			return bounds;
 		}
@@ -184,15 +167,17 @@ namespace bs
 
 		if (!mesh.isLoaded())
 		{
-			AABox box(mPosition, mPosition);
-			Sphere sphere(mPosition, 0.0f);
+			const Transform& tfrm = getTransform();
+
+			AABox box(tfrm.getPosition(), tfrm.getPosition());
+			Sphere sphere(tfrm.getPosition(), 0.0f);
 
 			return Bounds(box, sphere);
 		}
 		else
 		{
 			Bounds bounds = mesh->getProperties().getBounds();
-			bounds.transformAffine(mTransform);
+			bounds.transformAffine(mTfrmMatrix);
 
 			return bounds;
 		}
@@ -251,10 +236,10 @@ namespace bs
 		}
 	}
 
-	void Renderable::_updateTransform(const HSceneObject& so, bool force)
+	void Renderable::_updateState(const SceneObject& so, bool force)
 	{
-		UINT32 curHash = so->getTransformHash();
-		if (curHash != _getLastModifiedHash() || force)
+		UINT32 curHash = so.getTransformHash();
+		if (curHash != mHash || force)
 		{
 			// If skinned animation, don't include own transform since that will be handled by root bone animation
 			bool ignoreOwnTransform;
@@ -267,27 +252,23 @@ namespace bs
 			{
 				// Note: Technically we're checking child's hash but using parent's transform. Ideally we check the parent's
 				// hash to reduce the number of required updates.
-				HSceneObject parentSO = so->getParent();
+				HSceneObject parentSO = so.getParent();
 				if (parentSO != nullptr)
-				{
-					Matrix4 transformNoScale = Matrix4::TRS(parentSO->getWorldPosition(), parentSO->getWorldRotation(),
-						Vector3::ONE);
-					setTransform(parentSO->getWorldTfrm(), transformNoScale);
-				}
+					setTransform(parentSO->getTransform());
 				else
-					setTransform(Matrix4::IDENTITY, Matrix4::IDENTITY);
+					setTransform(Transform());
 			}
 			else
-			{
-				Matrix4 transformNoScale = Matrix4::TRS(so->getWorldPosition(), so->getWorldRotation(), Vector3::ONE);
-				setTransform(so->getWorldTfrm(), transformNoScale);
-			}
+				setTransform(so.getTransform());
 
-			_setLastModifiedHash(curHash);
+			mHash = curHash;
 		}
+
+		// Hash now matches so transform won't be applied twice, so we can just call base class version 
+		SceneActor::_updateState(so, force);
 	}
 
-	void Renderable::_markCoreDirty(RenderableDirtyFlag flag)
+	void Renderable::_markCoreDirty(ActorDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);
 	}
@@ -312,34 +293,31 @@ namespace bs
 		else
 			animationId = (UINT64)-1;
 
-		UINT32 size = rttiGetElemSize(mLayer) + 
+		UINT32 size =
+			getActorSyncDataSize() +
+			rttiGetElemSize(mLayer) + 
 			rttiGetElemSize(mOverrideBounds) + 
 			rttiGetElemSize(mUseOverrideBounds) +
 			rttiGetElemSize(numMaterials) + 
-			rttiGetElemSize(mTransform) +
-			rttiGetElemSize(mTransformNoScale) +
-			rttiGetElemSize(mPosition) +
-			rttiGetElemSize(mIsActive) +
+			rttiGetElemSize(mTfrmMatrix) +
+			rttiGetElemSize(mTfrmMatrixNoScale) +
 			rttiGetElemSize(animationId) +
 			rttiGetElemSize(mAnimType) + 
-			rttiGetElemSize(mMobility) +
 			rttiGetElemSize(getCoreDirtyFlags()) +
 			sizeof(SPtr<ct::Mesh>) +
 			numMaterials * sizeof(SPtr<ct::Material>);
 
 		UINT8* data = allocator->alloc(size);
 		char* dataPtr = (char*)data;
+		dataPtr = syncActorTo(dataPtr);
 		dataPtr = rttiWriteElem(mLayer, dataPtr);
 		dataPtr = rttiWriteElem(mOverrideBounds, dataPtr);
 		dataPtr = rttiWriteElem(mUseOverrideBounds, dataPtr);
 		dataPtr = rttiWriteElem(numMaterials, dataPtr);
-		dataPtr = rttiWriteElem(mTransform, dataPtr);
-		dataPtr = rttiWriteElem(mTransformNoScale, dataPtr);
-		dataPtr = rttiWriteElem(mPosition, dataPtr);
-		dataPtr = rttiWriteElem(mIsActive, dataPtr);
+		dataPtr = rttiWriteElem(mTfrmMatrix, dataPtr);
+		dataPtr = rttiWriteElem(mTfrmMatrixNoScale, dataPtr);
 		dataPtr = rttiWriteElem(animationId, dataPtr);
 		dataPtr = rttiWriteElem(mAnimType, dataPtr);
-		dataPtr = rttiWriteElem(mMobility, dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 
 		SPtr<ct::Mesh>* mesh = new (dataPtr) SPtr<ct::Mesh>();
@@ -438,7 +416,7 @@ namespace bs
 
 	Renderable::~Renderable()
 	{
-		if (mIsActive)
+		if (mActive)
 			gRenderer()->notifyRenderableRemoved(this);
 	}
 
@@ -456,7 +434,7 @@ namespace bs
 			Sphere sphere(mOverrideBounds.getCenter(), mOverrideBounds.getRadius());
 
 			Bounds bounds(mOverrideBounds, sphere);
-			bounds.transformAffine(mTransform);
+			bounds.transformAffine(mTfrmMatrix);
 
 			return bounds;
 		}
@@ -465,15 +443,17 @@ namespace bs
 
 		if (mesh == nullptr)
 		{
-			AABox box(mPosition, mPosition);
-			Sphere sphere(mPosition, 0.0f);
+			const Transform& tfrm = getTransform();
+
+			AABox box(tfrm.getPosition(), tfrm.getPosition());
+			Sphere sphere(tfrm.getPosition(), 0.0f);
 
 			return Bounds(box, sphere);
 		}
 		else
 		{
 			Bounds bounds = mesh->getProperties().getBounds();
-			bounds.transformAffine(mTransform);
+			bounds.transformAffine(mTfrmMatrix);
 
 			return bounds;
 		}
@@ -598,19 +578,17 @@ namespace bs
 
 		UINT32 numMaterials = 0;
 		UINT32 dirtyFlags = 0;
-		bool oldIsActive = mIsActive;
+		bool oldIsActive = mActive;
 
+		dataPtr = syncActorFrom(dataPtr);
 		dataPtr = rttiReadElem(mLayer, dataPtr);
 		dataPtr = rttiReadElem(mOverrideBounds, dataPtr);
 		dataPtr = rttiReadElem(mUseOverrideBounds, dataPtr);
 		dataPtr = rttiReadElem(numMaterials, dataPtr);
-		dataPtr = rttiReadElem(mTransform, dataPtr);
-		dataPtr = rttiReadElem(mTransformNoScale, dataPtr);
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mIsActive, dataPtr);
+		dataPtr = rttiReadElem(mTfrmMatrix, dataPtr);
+		dataPtr = rttiReadElem(mTfrmMatrixNoScale, dataPtr);
 		dataPtr = rttiReadElem(mAnimationId, dataPtr);
 		dataPtr = rttiReadElem(mAnimType, dataPtr);
-		dataPtr = rttiReadElem(mMobility, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 
 		SPtr<Mesh>* mesh = (SPtr<Mesh>*)dataPtr;
@@ -626,7 +604,7 @@ namespace bs
 			dataPtr += sizeof(SPtr<Material>);
 		}
 
-		if((dirtyFlags & (UINT32)RenderableDirtyFlag::Everything) != 0)
+		if((dirtyFlags & ((UINT32)ActorDirtyFlag::Everything | (UINT32)ActorDirtyFlag::Active)) != 0)
 		{
 			createAnimationBuffers();
 
@@ -644,9 +622,9 @@ namespace bs
 			else
 				mMorphVertexDeclaration = nullptr;
 
-			if (oldIsActive != mIsActive)
+			if (oldIsActive != mActive)
 			{
-				if (mIsActive)
+				if (mActive)
 					gRenderer()->notifyRenderableAdded(this);
 				else
 					gRenderer()->notifyRenderableRemoved(this);
@@ -657,16 +635,16 @@ namespace bs
 				gRenderer()->notifyRenderableAdded(this);
 			}
 		}
-		else if((dirtyFlags & (UINT32)RenderableDirtyFlag::Mobility) != 0)
+		else if((dirtyFlags & (UINT32)ActorDirtyFlag::Mobility) != 0)
 		{
 				gRenderer()->notifyRenderableRemoved(this);
 				gRenderer()->notifyRenderableAdded(this);
 		}
-		else if ((dirtyFlags & (UINT32)RenderableDirtyFlag::Transform) != 0)
+		else if ((dirtyFlags & (UINT32)ActorDirtyFlag::Transform) != 0)
 		{
-			if (mIsActive)
+			if (mActive)
 				gRenderer()->notifyRenderableUpdated(this);
 		}
 	}
 	}
-}
+}

+ 20 - 61
Source/BansheeCore/Renderer/BsRenderable.h

@@ -8,6 +8,7 @@
 #include "Resources/BsIResourceListener.h"
 #include "Math/BsBounds.h"
 #include "Math/BsAABox.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs
 {
@@ -17,14 +18,6 @@ namespace bs
 	 *  @{
 	 */
 
-	/**	Signals which portion of a Renderable is dirty. */
-	enum class RenderableDirtyFlag
-	{
-		Transform = 0x01,
-		Everything = 0x02,
-		Mobility = 0x04
-	};
-
 	/** Type of animation that can be applied to a renderable object. */
 	enum class RenderableAnimType
 	{
@@ -40,7 +33,7 @@ namespace bs
 	 * render any Renderable objects visible by a camera.
 	 */
 	template<bool Core>
-	class BS_CORE_EXPORT TRenderable
+	class BS_CORE_EXPORT TRenderable : public SceneActor
 	{
 		typedef typename TMeshType<Core>::Type MeshType;
 		typedef typename TMaterialPtrType<Core>::Type MaterialType;
@@ -49,6 +42,9 @@ namespace bs
 		TRenderable();
 		virtual ~TRenderable();
 
+		/** @copydoc SceneActor::setTransform */
+		void setTransform(const Transform& transform) override;
+
 		/**
 		 * Determines the mesh to render. All sub-meshes of the mesh will be rendered, and you may set individual materials
 		 * for each sub-mesh.
@@ -85,25 +81,6 @@ namespace bs
 		 */
 		void setLayer(UINT64 layer);
 
-		/** Sets the transform matrix that is applied to the object when its being rendered. */
-		void setTransform(const Matrix4& transform, const Matrix4& transformNoScale);
-
-		/**	Sets whether the object should be rendered or not. */
-		void setIsActive(bool active);
-
-		/**
-		 * Sets the mobility of a scene object. This is used primarily as a performance hint to engine systems. Objects
-		 * with more restricted mobility will result in higher performance. Some mobility constraints will be enforced by
-		 * the engine itself, while for others the caller must be sure not to break the promise he made when mobility was
-		 * set. By default scene object's mobility is unrestricted.
-		 */
-		void setMobility(ObjectMobility mobility);
-
-		/** 
-		 * Gets the mobility setting for this scene object. See setMobility(); 
-		 */
-		ObjectMobility getMobility() const { return mMobility; }
-	
 		/** 
 		 * Sets bounds that will be used when determining if object is visible. Only relevant if setUseOverrideBounds() is
 		 * set to true.
@@ -128,27 +105,15 @@ namespace bs
 		MaterialType getMaterial(UINT32 idx) const { return mMaterials[idx]; }
 
 		/**	Returns the transform matrix that is applied to the object when its being rendered. */
-		Matrix4 getTransform() const { return mTransform; }
+		Matrix4 getMatrix() const { return mTfrmMatrix; }
 
 		/**
 		 * Returns the transform matrix that is applied to the object when its being rendered. This transform matrix does 
 		 * not include scale values.
 		 */
-		Matrix4 getTransformNoScale() const { return mTransformNoScale; }
-
-		/**	Gets whether the object should be rendered or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**	Retrieves the world position of the renderable. */
-		Vector3 getPosition() const { return mPosition; }
+		Matrix4 getMatrixNoScale() const { return mTfrmMatrixNoScale; }
 
 	protected:
-		/** 
-		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
-		 * thread counterpart. 
-		 */
-		virtual void _markCoreDirty(RenderableDirtyFlag flag = RenderableDirtyFlag::Everything) { }
-
 		/**
 		 * Notifies the core object manager that this object is dependant on some other CoreObject(s), and the dependencies
 		 * changed since the last call to this method. This will trigger a call to getCoreDependencies() to collect the 
@@ -167,12 +132,9 @@ namespace bs
 		UINT64 mLayer;
 		AABox mOverrideBounds;
 		bool mUseOverrideBounds;
-		Vector3 mPosition;
-		Matrix4 mTransform;
-		Matrix4 mTransformNoScale;
-		bool mIsActive;
+		Matrix4 mTfrmMatrix;
+		Matrix4 mTfrmMatrixNoScale;
 		RenderableAnimType mAnimType;
-		ObjectMobility mMobility;
 	};
 
 	/** @} */
@@ -197,21 +159,19 @@ namespace bs
 		/**	Retrieves an implementation of a renderable handler usable only from the core thread. */
 		SPtr<ct::Renderable> getCore() const;
 
-		/**	Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/** Updates the transfrom from the provided scene object, if the scene object's data is detected to be dirty. */
-		void _updateTransform(const HSceneObject& so, bool force = false);
-
 		/**	Creates a new renderable handler instance. */
 		static SPtr<Renderable> create();
 
-	protected:
-		Renderable();
+		/**
+		 * @name Internal
+		 * @{
+		 */
+
+		/** @copydoc SceneActor::_updateState */
+		void _updateState(const SceneObject& so, bool force = false) override;
 
+		/** @} */
+	protected:
 		/** @copydoc CoreObject::createCore */
 		SPtr<ct::CoreObject> createCore() const override;
 
@@ -222,7 +182,7 @@ namespace bs
 		void refreshAnimation();
 
 		/** @copydoc TRenderable::_markCoreDirty */
-		void _markCoreDirty(RenderableDirtyFlag flag = RenderableDirtyFlag::Everything) override;
+		void _markCoreDirty(ActorDirtyFlag flag = ActorDirtyFlag::Everything) override;
 
 		/** @copydoc TRenderable::_markResourcesDirty */
 		void _markResourcesDirty() override;
@@ -248,7 +208,6 @@ namespace bs
 		/**	Creates a new renderable handler instance without initializing it. */
 		static SPtr<Renderable> createEmpty();
 
-		UINT32 mLastUpdateHash;
 		SPtr<Animation> mAnimation;
 
 		/************************************************************************/
@@ -323,4 +282,4 @@ namespace bs
 	}
 
 	/** @} */
-}
+}

+ 1 - 1
Source/BansheeCore/Scene/BsComponent.cpp

@@ -28,7 +28,7 @@ namespace bs
 
 	bool Component::calculateBounds(Bounds& bounds)
 	{
-		Vector3 position = SO()->getWorldPosition();
+		Vector3 position = SO()->getTransform().getPosition();
 
 		bounds = Bounds(AABox(position, position), Sphere(position, 0.0f));
 		return false;

+ 8 - 6
Source/BansheeCore/Scene/BsPrefabDiff.cpp

@@ -169,30 +169,32 @@ namespace bs
 			output->soFlags |= (UINT32)SceneObjectDiffFlags::Name;
 		}
 
-		if (prefab->getPosition() != instance->getPosition())
+		const Transform& prefabTfrm = prefab->getLocalTransform();
+		const Transform& instanceTfrm = instance->getLocalTransform();
+		if (prefabTfrm.getPosition() != instanceTfrm.getPosition())
 		{
 			if (output == nullptr)
 				output = bs_shared_ptr_new<PrefabObjectDiff>();
 
-			output->position = instance->getPosition();
+			output->position = instanceTfrm.getPosition();
 			output->soFlags |= (UINT32)SceneObjectDiffFlags::Position;
 		}
 
-		if (prefab->getRotation() != instance->getRotation())
+		if (prefabTfrm.getRotation() != instanceTfrm.getRotation())
 		{
 			if (output == nullptr)
 				output = bs_shared_ptr_new<PrefabObjectDiff>();
 
-			output->rotation = instance->getRotation();
+			output->rotation = instanceTfrm.getRotation();
 			output->soFlags |= (UINT32)SceneObjectDiffFlags::Rotation;
 		}
 
-		if (prefab->getScale() != instance->getScale())
+		if (prefabTfrm.getScale() != instanceTfrm.getScale())
 		{
 			if (output == nullptr)
 				output = bs_shared_ptr_new<PrefabObjectDiff>();
 
-			output->scale = instance->getScale();
+			output->scale = instanceTfrm.getScale();
 			output->soFlags |= (UINT32)SceneObjectDiffFlags::Scale;
 		}
 

+ 98 - 0
Source/BansheeCore/Scene/BsSceneActor.cpp

@@ -0,0 +1,98 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "Scene/BsSceneActor.h"
+#include "Scene/BsSceneObject.h"
+
+namespace bs
+{
+	SceneActor::SceneActor()
+		:mMobility(ObjectMobility::Movable), mActive(true), mHash(0)
+	{
+		
+	}
+
+	SceneActor::~SceneActor()
+	{
+		
+	}
+
+	void SceneActor::setTransform(const Transform& transform)
+	{
+		if (mMobility != ObjectMobility::Movable)
+			return;
+
+		mTransform = transform;
+		_markCoreDirty(ActorDirtyFlag::Transform);
+	}
+
+	void SceneActor::setMobility(ObjectMobility mobility)
+	{
+		mMobility = mobility;
+		_markCoreDirty(ActorDirtyFlag::Mobility);
+	}
+
+	void SceneActor::setActive(bool active)
+	{
+		mActive = active;
+		_markCoreDirty(ActorDirtyFlag::Active);
+	}
+
+	void SceneActor::_updateState(const SceneObject& so, bool force)
+	{
+		UINT32 curHash = so.getTransformHash();
+		if (curHash != mHash || force)
+		{
+			setTransform(so.getTransform());
+
+			mHash = curHash;
+		}
+
+		if (so.getActive() != mActive || force)
+			setActive(so.getActive());
+
+		if (so.getMobility() != mMobility || force)
+			setMobility(so.getMobility());
+	}
+
+	char* SceneActor::syncActorTo(char* data)
+	{
+		data = rttiWriteElem(mTransform.getPosition(), data);
+		data = rttiWriteElem(mTransform.getRotation(), data);
+		data = rttiWriteElem(mTransform.getScale(), data);
+		data = rttiWriteElem(mActive, data);
+		data = rttiWriteElem(mMobility, data);
+		
+		return data;
+	}
+
+	char* SceneActor::syncActorFrom(char* data)
+	{
+		Vector3 position;
+		Quaternion rotation;
+		Vector3 scale;
+
+		data = rttiReadElem(position, data);
+		data = rttiReadElem(rotation, data);
+		data = rttiReadElem(scale, data);
+		data = rttiReadElem(mActive, data);
+		data = rttiReadElem(mMobility, data);
+
+		mTransform.setPosition(position);
+		mTransform.setRotation(rotation);
+		mTransform.setScale(scale);
+
+		return data;
+	}
+
+	UINT32 SceneActor::getActorSyncDataSize() const
+	{
+		UINT32 size =
+			rttiGetElemSize(mTransform.getPosition()) +
+			rttiGetElemSize(mTransform.getRotation()) +
+			rttiGetElemSize(mTransform.getScale()) +
+			rttiGetElemSize(mActive) +
+			rttiGetElemSize(mMobility);
+
+		return size;
+	}
+}

+ 112 - 0
Source/BansheeCore/Scene/BsSceneActor.h

@@ -0,0 +1,112 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "Scene/BsTransform.h"
+
+namespace bs
+{
+	/** @addtogroup Scene-Internal
+	 *  @{
+	 */
+
+	/**	Signals which portion of a scene actor is dirty. */
+	enum class ActorDirtyFlag
+	{
+		Transform	= 1 << 0,
+		Mobility	= 1 << 1,
+		Active		= 1 << 2,
+		Everything	= 1 << 3
+	};
+
+	/**
+	 * A base class for objects that can be placed in the scene. It has a transform object that allows it to be positioned,
+	 * scaled and rotated, as well a properties that control its mobility (movable vs. immovable) and active status. 
+	 * 
+	 * In a way scene actors are similar to SceneObject%s, the main difference being that their implementations perform
+	 * some functionality directly, rather than relying on attached Components. Scene actors can be considered as a
+	 * lower-level alternative to SceneObject/Component model. In fact many Components internally just wrap scene actors.
+	 */
+	class BS_CORE_EXPORT SceneActor
+	{
+	public:
+		SceneActor();
+		virtual ~SceneActor();
+
+		/** Determines the position, rotation and scale of the actor. */
+		virtual void setTransform(const Transform& transform);
+
+		/** @copydoc setTransform */
+		const Transform& getTransform() const { return mTransform; }
+
+		/** Shorthand for getTransform(). */
+		const Transform& tfrm() const { return mTransform; }
+
+		/** 
+		 * Determines if the actor is currently active. Deactivated actors act as if they have been destroyed, without
+		 * actually being destroyed.
+		 */
+		virtual void setActive(bool active);
+
+		/** @copydoc setActive */
+		bool getActive() const { return mActive; }
+
+		/**
+		 * Determines the mobility of the actor. This is used primarily as a performance hint to engine systems. Objects
+		 * with more restricted mobility will result in higher performance. Any transform changes to immobile actors will
+		 * be ignored. By default actor's mobility is unrestricted.
+		 */
+		virtual void setMobility(ObjectMobility mobility);
+
+		/** @copydoc setMobility */
+		ObjectMobility getMobility() const { return mMobility; }
+
+		/** 
+		 * @name Internal
+		 * @{
+		 */
+		
+		/** 
+		 * Updates the internal actor state by transfering the relevant state from the scene object. The system tracks
+		 * the last state and only performs the update if the scene object was modified since the last call. You can force
+		 * an update by setting the @p force parameter to true. 
+		 * 
+		 * This method is used by the scene manager to update actors that have been bound to a scene object. Never call this
+		 * method for multiple different scene objects, as actor can only ever be bound to one during its lifetime.
+		 */
+		virtual void _updateState(const SceneObject& so, bool force = false);
+
+		/** @} */
+	protected:
+		/** 
+		 * Marks the simulation thread object as dirty and notifies the system its data should be synced with its core 
+		 * thread counterpart. 
+		 */
+		virtual void _markCoreDirty(ActorDirtyFlag flag = ActorDirtyFlag::Everything) { }
+
+		/** 
+		 * Writes the contents of this object into the provided data buffer. Buffer must have enough size of hold
+		 * getSyncActorDataSize() bytes. Returns the address after the last written byte.
+		 */
+		char* syncActorTo(char* data);
+
+		/** 
+		 * Reads the contents of this object from the provided data buffer. The buffer is expected to be populated by the
+		 * sim thread version of this object by calling syncActorTo(). Returns the address after the last read byte. 
+		 */
+		char* syncActorFrom(char* data);
+
+		/** Returns the size of the buffer required to store all data in this object, in bytes. */
+		UINT32 getActorSyncDataSize() const;
+	protected:
+		friend class SceneManager;
+
+		Transform mTransform;
+		ObjectMobility mMobility;
+		bool mActive;
+		UINT32 mHash;
+	};
+
+	/** @} */
+}

+ 37 - 138
Source/BansheeCore/Scene/BsSceneManager.cpp

@@ -6,11 +6,11 @@
 #include "Renderer/BsRenderable.h"
 #include "Renderer/BsCamera.h"
 #include "Renderer/BsLight.h"
-#include "Renderer/BsReflectionProbe.h"
 #include "RenderAPI/BsViewport.h"
 #include "Scene/BsGameObjectManager.h"
 #include "RenderAPI/BsRenderTarget.h"
 #include "Renderer/BsLightProbeVolume.h"
+#include "Scene/BsSceneActor.h"
 
 namespace bs
 {
@@ -85,29 +85,28 @@ namespace bs
 		oldRoot->destroy();
 	}
 
-	void SceneManager::_registerRenderable(const SPtr<Renderable>& renderable, const HSceneObject& so)
+	void SceneManager::_bindActor(const SPtr<SceneActor>& actor, const HSceneObject& so)
 	{
-		mRenderables[renderable.get()] = SceneRenderableData(renderable, so);
+		mBoundActors[actor.get()] = BoundActorData(actor, so);
 	}
 
-	void SceneManager::_unregisterRenderable(const SPtr<Renderable>& renderable)
+	void SceneManager::_unbindActor(const SPtr<SceneActor>& actor)
 	{
-		mRenderables.erase(renderable.get());
+		mBoundActors.erase(actor.get());
 	}
 
-	void SceneManager::_registerLight(const SPtr<Light>& light, const HSceneObject& so)
+	HSceneObject SceneManager::_getActorSO(const SPtr<SceneActor>& actor) const
 	{
-		mLights[light.get()] = SceneLightData(light, so);
-	}
+		auto iterFind = mBoundActors.find(actor.get());
+		if (iterFind != mBoundActors.end())
+			return iterFind->second.so;
 
-	void SceneManager::_unregisterLight(const SPtr<Light>& light)
-	{
-		mLights.erase(light.get());
+		return HSceneObject();		
 	}
 
-	void SceneManager::_registerCamera(const SPtr<Camera>& camera, const HSceneObject& so)
+	void SceneManager::_registerCamera(const SPtr<Camera>& camera)
 	{
-		mCameras[camera.get()] = SceneCameraData(camera, so);
+		mCameras[camera.get()] = camera;
 	}
 
 	void SceneManager::_unregisterCamera(const SPtr<Camera>& camera)
@@ -115,41 +114,21 @@ namespace bs
 		mCameras.erase(camera.get());
 
 		auto iterFind = std::find_if(mMainCameras.begin(), mMainCameras.end(),
-			[&](const SceneCameraData& x)
+			[&](const SPtr<Camera>& x)
 		{
-			return x.camera == camera;
+			return x == camera;
 		});
 
 		if (iterFind != mMainCameras.end())
 			mMainCameras.erase(iterFind);
 	}
 
-	void SceneManager::_registerReflectionProbe(const SPtr<ReflectionProbe>& probe, const HSceneObject& so)
-	{
-		mReflectionProbes[probe.get()] = SceneReflectionProbeData(probe, so);
-	}
-
-	void SceneManager::_unregisterReflectionProbe(const SPtr<ReflectionProbe>& probe)
-	{
-		mReflectionProbes.erase(probe.get());
-	}
-
-	void SceneManager::_registerLightProbeVolume(const SPtr<LightProbeVolume>& volume, const HSceneObject& so)
-	{
-		mLightProbeVolumes[volume.get()] = SceneLightProbeVolumeData(volume, so);
-	}
-
-	void SceneManager::_unregisterLightProbeVolume(const SPtr<LightProbeVolume>& volume)
-	{
-		mLightProbeVolumes.erase(volume.get());
-	}
-
 	void SceneManager::_notifyMainCameraStateChanged(const SPtr<Camera>& camera)
 	{
 		auto iterFind = std::find_if(mMainCameras.begin(), mMainCameras.end(),
-			[&](const SceneCameraData& entry)
+			[&](const SPtr<Camera>& entry)
 		{
-			return entry.camera == camera;
+			return entry == camera;
 		});
 
 		SPtr<Viewport> viewport = camera->getViewport();
@@ -172,101 +151,16 @@ namespace bs
 
 	void SceneManager::_updateCoreObjectTransforms()
 	{
-		for (auto& renderablePair : mRenderables)
-		{
-			SPtr<Renderable> renderable = renderablePair.second.renderable;
-			HSceneObject so = renderablePair.second.sceneObject;
-
-			if (so->getMobility() != renderable->getMobility())
-				renderable->setMobility(so->getMobility());
-
-			renderable->_updateTransform(so);
-
-			if (so->getActive() != renderable->getIsActive())
-				renderable->setIsActive(so->getActive());
-		}
-
-		for (auto& cameraPair : mCameras)
-		{
-			SPtr<Camera> handler = cameraPair.second.camera;
-			HSceneObject so = cameraPair.second.sceneObject;
-
-			UINT32 curHash = so->getTransformHash();
-			if (curHash != handler->_getLastModifiedHash())
-			{
-				handler->setPosition(so->getWorldPosition());
-				handler->setRotation(so->getWorldRotation());
-
-				handler->_setLastModifiedHash(curHash);
-			}
-
-			if (so->getActive() != handler->getIsActive())
-			{
-				handler->setIsActive(so->getActive());
-			}
-		}
-
-		for (auto& lightPair : mLights)
-		{
-			SPtr<Light> handler = lightPair.second.light;
-			HSceneObject so = lightPair.second.sceneObject;
-
-			if (so->getMobility() != handler->getMobility())
-				handler->setMobility(so->getMobility());
-
-			UINT32 curHash = so->getTransformHash();
-			if (curHash != handler->_getLastModifiedHash())
-			{
-				handler->setPosition(so->getWorldPosition());
-				handler->setRotation(so->getWorldRotation());
-
-				handler->_setLastModifiedHash(curHash);
-			}
-
-			if (so->getActive() != handler->getIsActive())
-			{
-				handler->setIsActive(so->getActive());
-			}
-		}
-
-		for (auto& probePair : mReflectionProbes)
-		{
-			SPtr<ReflectionProbe> probe = probePair.second.probe;
-			HSceneObject so = probePair.second.sceneObject;
-
-			UINT32 curHash = so->getTransformHash();
-			if (curHash != probe->_getLastModifiedHash())
-			{
-				probe->setPosition(so->getWorldPosition());
-				probe->setRotation(so->getWorldRotation());
-
-				probe->_setLastModifiedHash(curHash);
-			}
-
-			if (so->getActive() != probe->getIsActive())
-			{
-				probe->setIsActive(so->getActive());
-			}
-		}
-
-		for (auto& volumePair : mLightProbeVolumes)
-		{
-			SPtr<LightProbeVolume> volume = volumePair.second.volume;
-			HSceneObject so = volumePair.second.sceneObject;
-
-			volume->_updateTransform(so);
-
-			if (so->getActive() != volume->getIsActive())
-				volume->setIsActive(so->getActive());
-		}
+		for (auto& entry : mBoundActors)
+			entry.second.actor->_updateState(*entry.second.so);
 	}
 
-	SceneCameraData SceneManager::getMainCamera() const
+	SPtr<Camera> SceneManager::getMainCamera() const
 	{
 		if (mMainCameras.size() > 0)
 			return mMainCameras[0];
 
-		return SceneCameraData();
+		return nullptr;
 	}
 
 	void SceneManager::setMainRenderTarget(const SPtr<RenderTarget>& rt)
@@ -290,8 +184,8 @@ namespace bs
 
 		for (auto& entry : mMainCameras)
 		{
-			entry.camera->getViewport()->setTarget(rt);
-			entry.camera->setAspectRatio(aspect);
+			entry->getViewport()->setTarget(rt);
+			entry->setAspectRatio(aspect);
 		}
 	}
 
@@ -314,7 +208,7 @@ namespace bs
 				}
 
 				// Initialize and enable uninitialized components
-				for(auto& entry : mUnintializedComponents)
+				for(auto& entry : mUninitializedComponents)
 				{
 					entry->onInitialized();
 
@@ -336,7 +230,7 @@ namespace bs
 					}
 				}
 
-				mUnintializedComponents.clear();
+				mUninitializedComponents.clear();
 			}
 		}
 
@@ -427,8 +321,8 @@ namespace bs
 		}
 		else // Stopped
 		{
-			UINT32 idx = (UINT32)mUnintializedComponents.size();
-			mUnintializedComponents.push_back(component);
+			UINT32 idx = (UINT32)mUninitializedComponents.size();
+			mUninitializedComponents.push_back(component);
 
 			component->setSceneManagerId(encodeComponentId(idx, UninitializedList));
 		}
@@ -548,17 +442,17 @@ namespace bs
 		decodeComponentId(component->getSceneManagerId(), idx, listType);
 
 		UINT32 lastIdx;
-		decodeComponentId(mUnintializedComponents.back()->getSceneManagerId(), lastIdx, listType);
+		decodeComponentId(mUninitializedComponents.back()->getSceneManagerId(), lastIdx, listType);
 
-		assert(mUnintializedComponents[idx] == component);
+		assert(mUninitializedComponents[idx] == component);
 
 		if (idx != lastIdx)
 		{
-			std::swap(mUnintializedComponents[idx], mUnintializedComponents[lastIdx]);
-			mUnintializedComponents[idx]->setSceneManagerId(encodeComponentId(idx, UninitializedList));
+			std::swap(mUninitializedComponents[idx], mUninitializedComponents[lastIdx]);
+			mUninitializedComponents[idx]->setSceneManagerId(encodeComponentId(idx, UninitializedList));
 		}
 
-		mUnintializedComponents.erase(mUnintializedComponents.end() - 1);
+		mUninitializedComponents.erase(mUninitializedComponents.end() - 1);
 	}
 
 	UINT32 SceneManager::encodeComponentId(UINT32 idx, UINT32 type)
@@ -574,6 +468,11 @@ namespace bs
 		type = id >> 30;
 	}
 
+	bool SceneManager::isComponentOfType(const HComponent& component, UINT32 rttiId)
+	{
+		return component->getRTTI()->getRTTIId() == rttiId;
+	}
+
 	void SceneManager::_update()
 	{
 		// Note: Eventually perform updates based on component types and/or on component priority. Right now we just
@@ -597,7 +496,7 @@ namespace bs
 		float aspect = rtProps.width / (float)rtProps.height;
 
 		for (auto& entry : mMainCameras)
-			entry.camera->setAspectRatio(aspect);
+			entry->setAspectRatio(aspect);
 	}
 
 	SceneManager& gSceneManager()

+ 71 - 93
Source/BansheeCore/Scene/BsSceneManager.h

@@ -14,67 +14,17 @@ namespace bs
 	 *  @{
 	 */
 
-	/**	Contains information about a camera managed by the scene manager. */
-	struct SceneCameraData
+	/** Information about a scene actor and the scene object it has been bound to. */
+	struct BoundActorData
 	{
-		SceneCameraData() { }
+		BoundActorData() { }
 
-		SceneCameraData(const SPtr<Camera>& camera, const HSceneObject& sceneObject)
-			:camera(camera), sceneObject(sceneObject)
+		BoundActorData(const SPtr<SceneActor>& actor, const HSceneObject& so)
+			:actor(actor), so(so)
 		{ }
 
-		SPtr<Camera> camera;
-		HSceneObject sceneObject;
-	};
-
-	/**	Contains information about a renderable managed by the scene manager. */
-	struct SceneRenderableData
-	{
-		SceneRenderableData() { }
-
-		SceneRenderableData(const SPtr<Renderable>& renderable, const HSceneObject& sceneObject)
-			:renderable(renderable), sceneObject(sceneObject)
-		{ }
-
-		SPtr<Renderable> renderable;
-		HSceneObject sceneObject;
-	};
-
-	/**	Contains information about a light managed by the scene manager. */
-	struct SceneLightData
-	{
-		SceneLightData() { }
-
-		SceneLightData(const SPtr<Light>& light, const HSceneObject& sceneObject)
-			:light(light), sceneObject(sceneObject)
-		{ }
-
-		SPtr<Light> light;
-		HSceneObject sceneObject;
-	};
-
-	/**	Contains information about a reflection probe managed by the scene manager. */
-	struct SceneReflectionProbeData
-	{
-		SceneReflectionProbeData() { }
-		SceneReflectionProbeData(const SPtr<ReflectionProbe>& probe, const HSceneObject& sceneObject)
-			:probe(probe), sceneObject(sceneObject)
-		{ }
-
-		SPtr<ReflectionProbe> probe;
-		HSceneObject sceneObject;
-	};
-
-	/**	Contains information about a light probe volume managed by the scene manager. */
-	struct SceneLightProbeVolumeData
-	{
-		SceneLightProbeVolumeData() { }
-		SceneLightProbeVolumeData(const SPtr<LightProbeVolume>& volume, const HSceneObject& sceneObject)
-			:volume(volume), sceneObject(sceneObject)
-		{ }
-
-		SPtr<LightProbeVolume> volume;
-		HSceneObject sceneObject;
+		SPtr<SceneActor> actor;
+		HSceneObject so;
 	};
 
 	/** Possible states components can be in. Controls which component callbacks are triggered. */
@@ -85,7 +35,10 @@ namespace bs
 		Stopped /**< No component callbacks are being triggered. */
 	};
 
-	/** Manages active SceneObjects and provides ways for querying and updating them or their components. */
+	/** 
+	 * Keeps track of all active SceneObject%s and their components. Keeps track of component state and triggers their
+	 * events. Updates the transforms of objects as SceneObject%s move.
+	 */
 	class BS_CORE_EXPORT SceneManager : public Module<SceneManager>
 	{
 	public:
@@ -111,14 +64,25 @@ namespace bs
 		/** Checks are the components currently in the Running state. */
 		bool isRunning() const { return mComponentState == ComponentState::Running; }
 
+		/** 
+		 * Returns a list of all components of the specified type currently in the scene. 
+		 *
+		 * @tparam		T			Type of the component to search for.
+		 * 
+		 * @param[in]	activeOnly	If true only active components are returned, otherwise all components are returned.
+		 * @return					A list of all matching components in the scene.
+		 */
+		template<class T>
+		Vector<GameObjectHandle<T>> findComponents(bool activeOnly = true);
+
 		/** Returns all cameras in the scene. */
-		const Map<Camera*, SceneCameraData>& getAllCameras() const { return mCameras; }
+		const UnorderedMap<Camera*, SPtr<Camera>>& getAllCameras() const { return mCameras; }
 
 		/**
 		 * Returns the camera in the scene marked as main. Main camera controls the final render surface that is displayed
 		 * to the user. If there are multiple main cameras, the first one found returned.
 		 */
-		SceneCameraData getMainCamera() const;
+		SPtr<Camera> getMainCamera() const;
 
 		/**
 		 * Sets the render target that the main camera in the scene (if any) will render its view to. This generally means
@@ -126,39 +90,24 @@ namespace bs
 		 */
 		void setMainRenderTarget(const SPtr<RenderTarget>& rt);
 
-		/**	Returns all renderables in the scene. */
-		const Map<Renderable*, SceneRenderableData>& getAllRenderables() const { return mRenderables; }
-
-		/** Notifies the scene manager that a new renderable was created. */
-		void _registerRenderable(const SPtr<Renderable>& renderable, const HSceneObject& so);
-
-		/**	Notifies the scene manager that a renderable was removed. */
-		void _unregisterRenderable(const SPtr<Renderable>& renderable);
+		/** 
+		 * Binds a scene actor with a scene object. Every frame the scene object's transform will be monitored for
+		 * changes and those changes will be automatically transfered to the actor. 
+		 */
+		void _bindActor(const SPtr<SceneActor>& actor, const HSceneObject& so);
 
-		/**	Notifies the scene manager that a new light was created. */
-		void _registerLight(const SPtr<Light>& light, const HSceneObject& so);
+		/** Unbinds an actor that was previously bound using bindActor(). */
+		void _unbindActor(const SPtr<SceneActor>& actor);
 
-		/**	Notifies the scene manager that a light was removed. */
-		void _unregisterLight(const SPtr<Light>& light);
+		/** Returns a scene object bound to the provided actor, if any. */
+		HSceneObject _getActorSO(const SPtr<SceneActor>& actor) const;
 
 		/**	Notifies the scene manager that a new camera was created. */
-		void _registerCamera(const SPtr<Camera>& camera, const HSceneObject& so);
+		void _registerCamera(const SPtr<Camera>& camera);
 
 		/**	Notifies the scene manager that a camera was removed. */
 		void _unregisterCamera(const SPtr<Camera>& camera);
 
-		/**	Notifies the scene manager that a new reflection probe was created. */
-		void _registerReflectionProbe(const SPtr<ReflectionProbe>& probe, const HSceneObject& so);
-
-		/**	Notifies the scene manager that a reflection probe was removed. */
-		void _unregisterReflectionProbe(const SPtr<ReflectionProbe>& probe);
-
-		/**	Notifies the scene manager that a new light probe volume was created. */
-		void _registerLightProbeVolume(const SPtr<LightProbeVolume>& volume, const HSceneObject& so);
-
-		/**	Notifies the scene manager that a light proble volume was removed. */
-		void _unregisterLightProbeVolume(const SPtr<LightProbeVolume>& volume);
-
 		/**	Notifies the scene manager that a camera either became the main camera, or has stopped being main camera. */
 		void _notifyMainCameraStateChanged(const SPtr<Camera>& camera);
 
@@ -226,20 +175,19 @@ namespace bs
 		/** Decodes an id encoded with encodeComponentId(). */
 		void decodeComponentId(UINT32 id, UINT32& idx, UINT32& type);
 
+		/** Checks does the specified component type match the provided RTTI id. */
+		static bool isComponentOfType(const HComponent& component, UINT32 rttiId);
+
 	protected:
 		HSceneObject mRootNode;
 
-		Map<Camera*, SceneCameraData> mCameras;
-		Vector<SceneCameraData> mMainCameras;
-
-		Map<Renderable*, SceneRenderableData> mRenderables;
-		Map<Light*, SceneLightData> mLights;
-		Map<ReflectionProbe*, SceneReflectionProbeData> mReflectionProbes;
-		Map<LightProbeVolume*, SceneLightProbeVolumeData> mLightProbeVolumes;
+		UnorderedMap<SceneActor*, BoundActorData> mBoundActors;
+		UnorderedMap<Camera*, SPtr<Camera>> mCameras;
+		Vector<SPtr<Camera>> mMainCameras;
 
 		Vector<HComponent> mActiveComponents;
 		Vector<HComponent> mInactiveComponents;
-		Vector<HComponent> mUnintializedComponents;
+		Vector<HComponent> mUninitializedComponents;
 
 		SPtr<RenderTarget> mMainRT;
 		HEvent mMainRTResizedConn;
@@ -250,5 +198,35 @@ namespace bs
 	/**	Provides easy access to the SceneManager. */
 	BS_CORE_EXPORT SceneManager& gSceneManager();
 
+	template<class T>
+	Vector<GameObjectHandle<T>> SceneManager::findComponents(bool activeOnly)
+	{
+		UINT32 rttiId = T::getRTTIStatic()->getRTTIId();
+
+		Vector<GameObjectHandle<T>> output;
+		for(auto& entry : mActiveComponents)
+		{
+			if (isComponentOfType(entry, rttiId))
+				output.push_back(static_object_cast<T>(entry));
+		}
+
+		if(!activeOnly)
+		{
+			for(auto& entry : mInactiveComponents)
+			{
+				if (isComponentOfType(entry, rttiId))
+					output.push_back(static_object_cast<T>(entry));
+			}
+				
+			for(auto& entry : mUninitializedComponents)
+			{
+				if (isComponentOfType(entry, rttiId))
+					output.push_back(static_object_cast<T>(entry));
+			}
+		}
+
+		return output;
+	}
+
 	/** @} */
 }

+ 77 - 123
Source/BansheeCore/Scene/BsSceneObject.cpp

@@ -15,11 +15,9 @@
 namespace bs
 {
 	SceneObject::SceneObject(const String& name, UINT32 flags)
-		: GameObject(), mPrefabHash(0), mFlags(flags), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY)
-		, mScale(Vector3::ONE), mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY)
-		, mWorldScale(Vector3::ONE), mCachedLocalTfrm(Matrix4::IDENTITY), mCachedWorldTfrm(Matrix4::IDENTITY)
-		, mDirtyFlags(0xFFFFFFFF), mDirtyHash(0), mActiveSelf(true), mActiveHierarchy(true)
-		, mMobility(ObjectMobility::Movable)
+		: GameObject(), mPrefabHash(0), mFlags(flags), mCachedLocalTfrm(Matrix4::IDENTITY)
+		, mCachedWorldTfrm(Matrix4::IDENTITY), mDirtyFlags(0xFFFFFFFF), mDirtyHash(0), mActiveSelf(true)
+		, mActiveHierarchy(true), mMobility(ObjectMobility::Movable)
 	{
 		setName(name);
 	}
@@ -238,7 +236,7 @@ namespace bs
 	{
 		if (mMobility == ObjectMobility::Movable)
 		{
-			mPosition = position;
+			mLocalTfrm.setPosition(position);
 			notifyTransformChanged(TCF_Transform);
 		}
 	}
@@ -247,7 +245,7 @@ namespace bs
 	{
 		if (mMobility == ObjectMobility::Movable)
 		{
-			mRotation = rotation;
+			mLocalTfrm.setRotation(rotation);
 			notifyTransformChanged(TCF_Transform);
 		}
 	}
@@ -256,7 +254,7 @@ namespace bs
 	{
 		if (mMobility == ObjectMobility::Movable)
 		{
-			mScale = scale;
+			mLocalTfrm.setScale(scale);
 			notifyTransformChanged(TCF_Transform);
 		}
 	}
@@ -267,18 +265,9 @@ namespace bs
 			return;
 
 		if (mParent != nullptr)
-		{
-			Vector3 invScale = mParent->getWorldScale();
-			if (invScale.x != 0) invScale.x = 1.0f / invScale.x;
-			if (invScale.y != 0) invScale.y = 1.0f / invScale.y;
-			if (invScale.z != 0) invScale.z = 1.0f / invScale.z;
-
-			Quaternion invRotation = mParent->getWorldRotation().inverse();
-
-			mPosition = invRotation.rotate(position - mParent->getWorldPosition()) *  invScale;
-		}
+			mLocalTfrm.setWorldPosition(position, mParent->getTransform());
 		else
-			mPosition = position;
+			mLocalTfrm.setPosition(position);
 
 		notifyTransformChanged(TCF_Transform);
 	}
@@ -289,13 +278,9 @@ namespace bs
 			return;
 
 		if (mParent != nullptr)
-		{
-			Quaternion invRotation = mParent->getWorldRotation().inverse();
-
-			mRotation = invRotation * rotation;
-		}
+			mLocalTfrm.setWorldRotation(rotation, mParent->getTransform());
 		else
-			mRotation = rotation;
+			mLocalTfrm.setRotation(rotation);
 
 		notifyTransformChanged(TCF_Transform);
 	}
@@ -306,60 +291,33 @@ namespace bs
 			return;
 
 		if (mParent != nullptr)
-		{
-			Matrix3 rotScale;
-			mParent->getWorldTfrm().extract3x3Matrix(rotScale);
-			rotScale.inverse();
-
-			Matrix3 scaleMat = Matrix3(Quaternion::IDENTITY, scale);
-			scaleMat = rotScale * scaleMat;
-
-			Quaternion rotation;
-			Vector3 localScale;
-			scaleMat.decomposition(rotation, localScale);
-
-			mScale = localScale;
-		}
+			mLocalTfrm.setWorldScale(scale, mParent->getTransform());
 		else
-			mScale = scale;
+			mLocalTfrm.setScale(scale);
 
 		notifyTransformChanged(TCF_Transform);
 	}
 
-	const Vector3& SceneObject::getWorldPosition() const
-	{ 
-		if (!isCachedWorldTfrmUpToDate())
-			updateWorldTfrm();
-
-		return mWorldPosition; 
-	}
-
-	const Quaternion& SceneObject::getWorldRotation() const 
+	const Transform& SceneObject::getTransform() const
 	{ 
 		if (!isCachedWorldTfrmUpToDate())
 			updateWorldTfrm();
 
-		return mWorldRotation; 
-	}
-
-	const Vector3& SceneObject::getWorldScale() const 
-	{ 
-		if (!isCachedWorldTfrmUpToDate())
-			updateWorldTfrm();
-
-		return mWorldScale; 
+		return mWorldTfrm; 
 	}
 
 	void SceneObject::lookAt(const Vector3& location, const Vector3& up)
 	{
-		Vector3 forward = location - getWorldPosition();
+		const Transform& worldTfrm = getTransform();
+
+		Vector3 forward = location - worldTfrm.getPosition();
 		
-		Quaternion rotation = getWorldRotation();
+		Quaternion rotation = worldTfrm.getRotation();
 		rotation.lookRotation(forward, up);
 		setWorldRotation(rotation);
 	}
 
-	const Matrix4& SceneObject::getWorldTfrm() const
+	const Matrix4& SceneObject::getWorldMatrix() const
 	{
 		if (!isCachedWorldTfrmUpToDate())
 			updateWorldTfrm();
@@ -367,16 +325,16 @@ namespace bs
 		return mCachedWorldTfrm;
 	}
 
-	Matrix4 SceneObject::getInvWorldTfrm() const
+	Matrix4 SceneObject::getInvWorldMatrix() const
 	{
 		if (!isCachedWorldTfrmUpToDate())
 			updateWorldTfrm();
 
-		Matrix4 worldToLocal = Matrix4::inverseTRS(mWorldPosition, mWorldRotation, mWorldScale);
+		Matrix4 worldToLocal = mWorldTfrm.getInvMatrix();
 		return worldToLocal;
 	}
 
-	const Matrix4& SceneObject::getLocalTfrm() const
+	const Matrix4& SceneObject::getLocalMatrix() const
 	{
 		if (!isCachedLocalTfrmUpToDate())
 			updateLocalTfrm();
@@ -386,57 +344,72 @@ namespace bs
 
 	void SceneObject::move(const Vector3& vec)
 	{
-		setPosition(mPosition + vec);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.move(vec);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::moveRelative(const Vector3& vec)
 	{
-		// Transform the axes of the relative vector by camera's local axes
-		Vector3 trans = mRotation.rotate(vec);
-
-		setPosition(mPosition + trans);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.moveRelative(vec);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::rotate(const Vector3& axis, const Radian& angle)
 	{
-		Quaternion q;
-		q.fromAxisAngle(axis, angle);
-		rotate(q);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.rotate(axis, angle);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::rotate(const Quaternion& q)
 	{
-		// Note the order of the mult, i.e. q comes after
-
-		// Normalize the quat to avoid cumulative problems with precision
-		Quaternion qnorm = q;
-		qnorm.normalize();
-		setRotation(qnorm * mRotation);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.rotate(q);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::roll(const Radian& angle)
 	{
-		// Rotate around local Z axis
-		Vector3 zAxis = mRotation.rotate(Vector3::UNIT_Z);
-		rotate(zAxis, angle);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.roll(angle);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::yaw(const Radian& angle)
 	{
-		Vector3 yAxis = mRotation.rotate(Vector3::UNIT_Y);
-		rotate(yAxis, angle);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.yaw(angle);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::pitch(const Radian& angle)
 	{
-		// Rotate around local X axis
-		Vector3 xAxis = mRotation.rotate(Vector3::UNIT_X);
-		rotate(xAxis, angle);
+		if (mMobility == ObjectMobility::Movable)
+		{
+			mLocalTfrm.pitch(angle);
+			notifyTransformChanged(TCF_Transform);
+		}
 	}
 
 	void SceneObject::setForward(const Vector3& forwardDir)
 	{
-		Quaternion currentRotation = getWorldRotation();
+		const Transform& worldTfrm = getTransform();
+
+		Quaternion currentRotation = worldTfrm.getRotation();
 		currentRotation.lookRotation(forwardDir);
 		setWorldRotation(currentRotation);
 	}
@@ -487,34 +460,18 @@ namespace bs
 
 	void SceneObject::updateWorldTfrm() const
 	{
+		mWorldTfrm = mLocalTfrm;
+
 		// Don't allow movement from parent when not movable
 		if (mParent != nullptr && mMobility == ObjectMobility::Movable)
 		{
-			// Update orientation
-			const Quaternion& parentOrientation = mParent->getWorldRotation();
-			mWorldRotation = parentOrientation * mRotation;
-
-			// Update scale
-			const Vector3& parentScale = mParent->getWorldScale();
-			// Scale own position by parent scale, just combine
-			// as equivalent axes, no shearing
-			mWorldScale = parentScale * mScale;
-
-			// Change position vector based on parent's orientation & scale
-			mWorldPosition = parentOrientation.rotate(parentScale * mPosition);
+			mWorldTfrm.makeWorld(mParent->getTransform());
 
-			// Add altered position vector to parents
-			mWorldPosition += mParent->getWorldPosition();
-
-			mCachedWorldTfrm.setTRS(mWorldPosition, mWorldRotation, mWorldScale);
+			mCachedWorldTfrm = mWorldTfrm.getMatrix();
 		}
 		else
 		{
-			mWorldRotation = mRotation;
-			mWorldPosition = mPosition;
-			mWorldScale = mScale;
-
-			mCachedWorldTfrm = getLocalTfrm();
+			mCachedWorldTfrm = getLocalMatrix();
 		}
 
 		mDirtyFlags &= ~DirtyFlags::WorldTfrmDirty;
@@ -522,8 +479,7 @@ namespace bs
 
 	void SceneObject::updateLocalTfrm() const
 	{
-		mCachedLocalTfrm.setTRS(mPosition, mRotation, mScale);
-
+		mCachedLocalTfrm = mLocalTfrm.getMatrix();
 		mDirtyFlags &= ~DirtyFlags::LocalTfrmDirty;
 	}
 
@@ -540,6 +496,9 @@ namespace bs
 		String originalPrefab = getPrefabLink();
 #endif
 
+		if (mMobility != ObjectMobility::Movable)
+			keepWorldTransform = true;
+
 		_setParent(parent, keepWorldTransform);
 
 #if BS_EDITOR_BUILD
@@ -559,17 +518,11 @@ namespace bs
 
 		if (mParent == nullptr || mParent != parent)
 		{
-			Vector3 worldPos;
-			Quaternion worldRot;
-			Vector3 worldScale;
+			Transform worldTfrm;
 
+			// Make sure the object keeps its world coordinates
 			if (keepWorldTransform)
-			{
-				// Make sure the object keeps its world coordinates
-				worldPos = getWorldPosition();
-				worldRot = getWorldRotation();
-				worldScale = getWorldScale();
-			}
+				worldTfrm = getTransform();
 
 			if (mParent != nullptr)
 				mParent->removeChild(mThisHandle);
@@ -581,9 +534,10 @@ namespace bs
 
 			if (keepWorldTransform)
 			{
-				setWorldPosition(worldPos);
-				setWorldRotation(worldRot);
-				setWorldScale(worldScale);
+				mLocalTfrm = worldTfrm;
+
+				if (mParent != nullptr)
+					mLocalTfrm.makeLocal(mParent->getTransform());
 			}
 
 			notifyTransformChanged((TransformChangedFlags)(TCF_Parent | TCF_Transform));
@@ -747,7 +701,7 @@ namespace bs
 		}
 	}
 
-	bool SceneObject::getActive(bool self)
+	bool SceneObject::getActive(bool self) const
 	{
 		if (self)
 			return mActiveSelf;

+ 19 - 64
Source/BansheeCore/Scene/BsSceneObject.h

@@ -10,6 +10,7 @@
 #include "Scene/BsGameObjectManager.h"
 #include "Scene/BsGameObject.h"
 #include "Scene/BsComponent.h"
+#include "Scene/BsTransform.h"
 
 namespace bs
 {
@@ -30,8 +31,12 @@ namespace bs
 	};
 
 	/**
-	 * An object in the scene graph. It has a world position, place in the hierarchy and optionally a number of attached 
-	 * components.
+	 * An object in the scene graph. It has a transform object that allows it to be positioned, scaled and rotated. It can
+	 * have other scene objects as children, and will have a scene object as a parent, in which case transform changes
+	 * to the parent are reflected to the child scene objects (children are relative to the parent).
+	 * 
+	 * Each scene object can have one or multiple Component%s attached to it, where the components inherit the scene
+	 * object's transform, and receive updates about transform and hierarchy changes.
 	 */
 	class BS_CORE_EXPORT SceneObject : public GameObject
 	{
@@ -190,44 +195,27 @@ namespace bs
 		/* 								Transform	                     		*/
 		/************************************************************************/
 	public:
+		/** Gets the transform object representing object's position/rotation/scale in world space. */
+		const Transform& getTransform() const;
+
+		/** Gets the transform object representing object's position/rotation/scale relative to its parent. */
+		const Transform& getLocalTransform() const { return mLocalTfrm; }
+
 		/**	Sets the local position of the object. */
 		void setPosition(const Vector3& position);
 
-		/**	Gets the local position of the object. */
-		const Vector3& getPosition() const { return mPosition; }
-
 		/**	Sets the world position of the object. */
 		void setWorldPosition(const Vector3& position);
 
-		/**
-		 * Gets the world position of the object.
-		 *
-		 * @note	Performance warning: This might involve updating the transforms if the transform is dirty.
-		 */
-		const Vector3& getWorldPosition() const;
-
 		/**	Sets the local rotation of the object. */
 		void setRotation(const Quaternion& rotation);
 
-		/**	Gets the local rotation of the object. */
-		const Quaternion& getRotation() const { return mRotation; }
-
 		/**	Sets the world rotation of the object. */
 		void setWorldRotation(const Quaternion& rotation);
 
-		/**
-		 * Gets world rotation of the object.
-		 *
-		 * @note	Performance warning: This might involve updating the transforms if the transform is dirty.
-		 */
-		const Quaternion& getWorldRotation() const;
-
 		/**	Sets the local scale of the object. */
 		void setScale(const Vector3& scale);
 
-		/**	Gets the local scale of the object. */
-		const Vector3& getScale() const { return mScale; }
-
 		/**
 		 * Sets the world scale of the object.
 		 *
@@ -235,13 +223,6 @@ namespace bs
 		 */
 		void setWorldScale(const Vector3& scale);
 
-		/**
-		 * Gets world scale of the object.
-		 *
-		 * @note	Performance warning: This might involve updating the transforms if the transform is dirty.
-		 */
-		const Vector3& getWorldScale() const;
-
 		/**
 		 * Orients the object so it is looking at the provided @p location (world space) where @p up is used for 
 		 * determining the location of the object's Y axis.
@@ -253,17 +234,17 @@ namespace bs
 		 *
 		 * @note	Performance warning: This might involve updating the transforms if the transform is dirty.
 		 */
-		const Matrix4& getWorldTfrm() const;
+		const Matrix4& getWorldMatrix() const;
 
 		/**
 		 * Gets the objects inverse world transform matrix.
 		 *
 		 * @note	Performance warning: This might involve updating the transforms if the transform is dirty.
 		 */
-		Matrix4 getInvWorldTfrm() const;
+		Matrix4 getInvWorldMatrix() const;
 
 		/** Gets the objects local transform matrix. */
-		const Matrix4& getLocalTfrm() const;
+		const Matrix4& getLocalMatrix() const;
 
 		/**	Moves the object's position by the vector offset provided along world axes. */
 		void move(const Vector3& vec);
@@ -271,27 +252,6 @@ namespace bs
 		/**	Moves the object's position by the vector offset provided along it's own axes (relative to orientation). */
 		void moveRelative(const Vector3& vec);
 
-		/**
-		 * Gets the Z (forward) axis of the object, in world space.
-		 *
-		 * @return	Forward axis of the object.
-		 */
-		Vector3 getForward() const { return getWorldRotation().rotate(-Vector3::UNIT_Z); }
-
-		/**
-		 * Gets the Y (up) axis of the object, in world space.
-		 *
-		 * @return	Up axis of the object.
-		 */
-		Vector3 getUp() const { return getWorldRotation().rotate(Vector3::UNIT_Y); }
-
-		/**
-		 * Gets the X (right) axis of the object, in world space.
-		 *
-		 * @return	Right axis of the object.
-		 */
-		Vector3 getRight() const { return getWorldRotation().rotate(Vector3::UNIT_X); }
-
 		/**
 		 * Rotates the game object so it's forward axis faces the provided direction.
 		 *
@@ -344,13 +304,8 @@ namespace bs
 		UINT32 getTransformHash() const { return mDirtyHash; }
 
 	private:
-		Vector3 mPosition;
-		Quaternion mRotation;
-		Vector3 mScale;
-
-		mutable Vector3 mWorldPosition;
-		mutable Quaternion mWorldRotation;
-		mutable Vector3 mWorldScale;
+		Transform mLocalTfrm;
+		mutable Transform mWorldTfrm;
 
 		mutable Matrix4 mCachedLocalTfrm;
 		mutable Matrix4 mCachedWorldTfrm;
@@ -461,7 +416,7 @@ namespace bs
 		 * @param[in]	self	If true, the method will only check if this particular object was activated or deactivated
 		 *						directly via setActive. If false we we also check if any of the objects parents are inactive.
 		 */
-		bool getActive(bool self = false);
+		bool getActive(bool self = false) const;
 
 		/**
 		 * Sets the mobility of a scene object. This is used primarily as a performance hint to engine systems. Objects

+ 158 - 0
Source/BansheeCore/Scene/BsTransform.cpp

@@ -0,0 +1,158 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "Scene/BsTransform.h"
+#include "RTTI/BsTransformRTTI.h"
+
+namespace bs
+{
+	Transform::Transform()
+		: mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::ONE)
+	{ }
+
+	Matrix4 Transform::getMatrix() const
+	{
+		return Matrix4::TRS(mPosition, mRotation, mScale);
+	}
+
+	Matrix4 Transform::getInvMatrix() const
+	{
+		return Matrix4::inverseTRS(mPosition, mRotation, mScale);
+	}
+
+	void Transform::makeLocal(const Transform& parent)
+	{
+		setWorldPosition(mPosition, parent);
+		setWorldRotation(mRotation, parent);
+		setWorldScale(mScale, parent);
+	}
+
+	void Transform::makeWorld(const Transform& parent)
+	{
+		// Update orientation
+		const Quaternion& parentOrientation = parent.getRotation();
+		mRotation = parentOrientation * mRotation;
+
+		// Update scale
+		const Vector3& parentScale = parent.getScale();
+
+		// Scale own position by parent scale, just combine as equivalent axes, no shearing
+		mScale = parentScale * mScale;
+
+		// Change position vector based on parent's orientation & scale
+		mPosition = parentOrientation.rotate(parentScale * mPosition);
+
+		// Add altered position vector to parents
+		mPosition += parent.getPosition();
+	}
+
+	void Transform::setWorldPosition(const Vector3& position, const Transform& parent)
+	{
+		Vector3 invScale = parent.getScale();
+		if (invScale.x != 0) invScale.x = 1.0f / invScale.x;
+		if (invScale.y != 0) invScale.y = 1.0f / invScale.y;
+		if (invScale.z != 0) invScale.z = 1.0f / invScale.z;
+
+		Quaternion invRotation = parent.getRotation().inverse();
+
+		mPosition = invRotation.rotate(position - parent.getPosition()) *  invScale;
+	}
+
+	void Transform::setWorldRotation(const Quaternion& rotation, const Transform& parent)
+	{
+		Quaternion invRotation = parent.getRotation().inverse();
+		mRotation = invRotation * rotation;
+	}
+
+	void Transform::setWorldScale(const Vector3& scale, const Transform& parent)
+	{
+		Matrix3 rotScale;
+		Matrix4 parentMatrix = parent.getMatrix();
+		parentMatrix.extract3x3Matrix(rotScale);
+		rotScale.inverse();
+
+		Matrix3 scaleMat = Matrix3(Quaternion::IDENTITY, scale);
+		scaleMat = rotScale * scaleMat;
+
+		Quaternion rotation;
+		Vector3 localScale;
+		scaleMat.decomposition(rotation, localScale);
+
+		mScale = localScale;
+	}
+
+	void Transform::lookAt(const Vector3& location, const Vector3& up)
+	{
+		Vector3 forward = location - getPosition();
+		
+		Quaternion rotation = getRotation();
+		rotation.lookRotation(forward, up);
+		setRotation(rotation);
+	}
+
+	void Transform::move(const Vector3& vec)
+	{
+		setPosition(mPosition + vec);
+	}
+
+	void Transform::moveRelative(const Vector3& vec)
+	{
+		// Transform the axes of the relative vector by camera's local axes
+		Vector3 trans = mRotation.rotate(vec);
+
+		setPosition(mPosition + trans);
+	}
+
+	void Transform::rotate(const Vector3& axis, const Radian& angle)
+	{
+		Quaternion q;
+		q.fromAxisAngle(axis, angle);
+		rotate(q);
+	}
+
+	void Transform::rotate(const Quaternion& q)
+	{
+		// Note the order of the mult, i.e. q comes after
+
+		// Normalize the quat to avoid cumulative problems with precision
+		Quaternion qnorm = q;
+		qnorm.normalize();
+		setRotation(qnorm * mRotation);
+	}
+
+	void Transform::roll(const Radian& angle)
+	{
+		// Rotate around local Z axis
+		Vector3 zAxis = mRotation.rotate(Vector3::UNIT_Z);
+		rotate(zAxis, angle);
+	}
+
+	void Transform::yaw(const Radian& angle)
+	{
+		Vector3 yAxis = mRotation.rotate(Vector3::UNIT_Y);
+		rotate(yAxis, angle);
+	}
+
+	void Transform::pitch(const Radian& angle)
+	{
+		// Rotate around local X axis
+		Vector3 xAxis = mRotation.rotate(Vector3::UNIT_X);
+		rotate(xAxis, angle);
+	}
+
+	void Transform::setForward(const Vector3& forwardDir)
+	{
+		Quaternion currentRotation = getRotation();
+		currentRotation.lookRotation(forwardDir);
+		setRotation(currentRotation);
+	}
+
+	RTTITypeBase* Transform::getRTTIStatic()
+	{
+		return TransformRTTI::instance();
+	}
+
+	RTTITypeBase* Transform::getRTTI() const
+	{
+		return Transform::getRTTIStatic();
+	}
+}

+ 171 - 0
Source/BansheeCore/Scene/BsTransform.h

@@ -0,0 +1,171 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "Math/BsMatrix4.h"
+#include "Math/BsVector3.h"
+#include "Math/BsQuaternion.h"
+#include "Reflection/BsRTTIType.h"
+
+namespace bs
+{
+	/** @addtogroup Scene
+	 *  @{
+	 */
+
+	/** 
+	 * Contains information about 3D object's position, rotation and scale, and provides methods to manipulate it. 
+	 */
+	class BS_CORE_EXPORT Transform : public IReflectable
+	{
+	public:
+		Transform();
+
+		/**	Sets the local position of the object. */
+		void setPosition(const Vector3& position) { mPosition = position; }
+
+		/**	Gets the local position of the object. */
+		const Vector3& getPosition() const { return mPosition; }
+
+		/** Shorthand for getPosition(). */
+		const Vector3& pos() const { return mPosition; }
+
+		/**	Sets the local rotation of the object. */
+		void setRotation(const Quaternion& rotation) { mRotation = rotation; }
+
+		/**	Gets the local rotation of the object. */
+		const Quaternion& getRotation() const { return mRotation; }
+
+		/** Shorthand for getRotation(). */
+		const Quaternion& rot() const { return mRotation; }
+
+		/**	Sets the local scale of the object. */
+		void setScale(const Vector3& scale) { mScale = scale; }
+
+		/**	Gets the local scale of the object. */
+		const Vector3& getScale() const { return mScale; }
+
+		/** Shorthand for getScale(). */
+		const Vector3& scl() const { return mScale; }
+
+		/** 
+		 * Converts the provided world position to a space relative to the provided parent, as sets it as the current
+		 * transform's position. 
+		 */
+		void setWorldPosition(const Vector3& position, const Transform& parent);
+
+		/** 
+		 * Converts the provided world rotation to a space relative to the provided parent, as sets it as the current
+		 * transform's rotation. 
+		 */
+		void setWorldRotation(const Quaternion& rotation, const Transform& parent);
+
+		/** 
+		 * Converts the provided world scale to a space relative to the provided parent, as sets it as the current
+		 * transform's scale. 
+		 */
+		void setWorldScale(const Vector3& scale, const Transform& parent);
+
+		/** Builds the transform matrix from current properties. */
+		Matrix4 getMatrix() const;
+
+		/** Builds the inverse transform matrix from current properties. */
+		Matrix4 getInvMatrix() const;
+
+		/** 
+		 * Makes the current transform relative to the provided transform. In another words, converts from a world 
+		 * coordinate system to one local to the provided transform. 
+		 */
+		void makeLocal(const Transform& parent);
+
+		/**
+		 * Makes the current transform absolute. In another words, converts from a local coordinate system relative to
+		 * the provided transform, to a world coordinate system.
+		 */
+		void makeWorld(const Transform& parent);
+
+		/**
+		 * Orients the object so it is looking at the provided @p location (world space) where @p up is used for 
+		 * determining the location of the object's Y axis.
+		 */
+		void lookAt(const Vector3& location, const Vector3& up = Vector3::UNIT_Y);
+
+		/**	Moves the object's position by the vector offset provided along world axes. */
+		void move(const Vector3& vec);
+
+		/**	Moves the object's position by the vector offset provided along it's own axes (relative to orientation). */
+		void moveRelative(const Vector3& vec);
+
+		/**
+		 * Gets the Z (forward) axis of the object.
+		 *
+		 * @return	Forward axis of the object.
+		 */
+		Vector3 getForward() const { return getRotation().rotate(-Vector3::UNIT_Z); }
+
+		/**
+		 * Gets the Y (up) axis of the object.
+		 *
+		 * @return	Up axis of the object.
+		 */
+		Vector3 getUp() const { return getRotation().rotate(Vector3::UNIT_Y); }
+
+		/**
+		 * Gets the X (right) axis of the object.
+		 *
+		 * @return	Right axis of the object.
+		 */
+		Vector3 getRight() const { return getRotation().rotate(Vector3::UNIT_X); }
+
+		/**
+		 * Rotates the game object so it's forward axis faces the provided direction.
+		 *
+		 * @param[in]	forwardDir	The forward direction to face.
+		 *
+		 * @note	Local forward axis is considered to be negative Z.
+		 */
+		void setForward(const Vector3& forwardDir);
+
+		/**	Rotate the object around an arbitrary axis. */
+		void rotate(const Vector3& axis, const Radian& angle);
+
+		/**	Rotate the object around an arbitrary axis using a Quaternion. */
+		void rotate(const Quaternion& q);
+
+		/**
+		 * Rotates around local Z axis.
+		 *
+		 * @param[in]	angle	Angle to rotate by.
+		 */
+		void roll(const Radian& angle);
+
+		/**
+		 * Rotates around Y axis.
+		 *
+		 * @param[in]	angle	Angle to rotate by.
+		 */
+		void yaw(const Radian& angle);
+
+		/**
+		 * Rotates around X axis
+		 *
+		 * @param[in]	angle	Angle to rotate by.
+		 */
+		void pitch(const Radian& angle);
+	private:
+		Vector3 mPosition;
+		Quaternion mRotation;
+		Vector3 mScale;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class TransformRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+	};
+
+	/** @} */
+}

+ 15 - 0
Source/BansheeEditor/BsEditorApplication.cpp

@@ -147,6 +147,21 @@ namespace bs
 		loadPlugin("SBansheeEditor", &mSBansheeEditorPlugin);
 	}
 
+	void EditorApplication::unloadScriptSystem()
+	{
+		// These plugins must be unloaded before any other script plugins, because
+		// they will cause finalizers to trigger and various modules those finalizers
+		// might reference must still be active
+		if(mSBansheeEditorPlugin != nullptr)
+			unloadPlugin(mSBansheeEditorPlugin);
+
+		if(mSBansheeEnginePlugin != nullptr)
+			unloadPlugin(mSBansheeEnginePlugin);
+
+		if(mMonoPlugin != nullptr)
+			unloadPlugin(mMonoPlugin);
+	}
+
 	void EditorApplication::startUp()
 	{
 		CoreApplication::startUp<EditorApplication>();

+ 3 - 0
Source/BansheeEditor/BsEditorApplication.h

@@ -100,6 +100,9 @@ namespace bs
 		/** @copydoc Application::loadScriptSystem */
 		void loadScriptSystem() override;
 
+		/** @copydoc Application::unloadScriptSystem */
+		void unloadScriptSystem() override;
+
 		/**
 		 * Loads the previously saved editor widget layout from the default location. Can return null if no layout was 
 		 * previously saved.

+ 2 - 1
Source/BansheeEditor/CodeEditor/BsMDCodeEditor.cpp

@@ -4,10 +4,11 @@
 #include "FileSystem/BsFileSystem.h"
 #include "FileSystem/BsDataStream.h"
 #include "String/BsUnicode.h"
-#include "Linux/BsLinuxPlatform.h"
 
 #if BS_PLATFORM == BS_PLATFORM_WIN32
 #include <Windows.h>
+#elif BS_PLATFORM == BS_PLATFORM_LINUX
+#include "Linux/BsLinuxPlatform.h"
 #endif
 
 namespace bs

+ 3 - 2
Source/BansheeEditor/Handles/BsHandleDrawManager.cpp

@@ -178,7 +178,8 @@ namespace bs
 			mLastFrameIdx = frameIdx;
 		}
 
-		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition(), camera->getLayers());
+		const Transform& tfrm = camera->getTransform();
+		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, tfrm.getPosition(), camera->getLayers());
 
 		const Vector<DrawHelper::ShapeMeshData>& meshes = mDrawHelper->getMeshes();
 		mActiveMeshes.push_back(meshes);
@@ -332,7 +333,7 @@ namespace bs
 			Matrix4 viewProjMat = camera.getProjectionMatrixRS() * camera.getViewMatrix();
 
 			gHandleParamBlockDef.gMatViewProj.set(mParamBuffer, viewProjMat);
-			gHandleParamBlockDef.gViewDir.set(mParamBuffer, (Vector4)camera.getForward());
+			gHandleParamBlockDef.gViewDir.set(mParamBuffer, (Vector4)camera.getTransform().getForward());
 
 			UINT32 currentType = -1;
 			for (auto& meshData : meshes)

+ 3 - 2
Source/BansheeEditor/Handles/BsHandleManager.cpp

@@ -96,10 +96,11 @@ namespace bs
 	{
 		if (camera->getProjectionType() == PT_PERSPECTIVE)
 		{
-			Vector3 cameraPos = camera->getPosition();
+			const Transform& tfrm = camera->getTransform();
+			Vector3 cameraPos = tfrm.getPosition();
 
 			Vector3 diff = handlePos - cameraPos;
-			float distAlongViewDir = Math::abs(diff.dot(camera->getRotation().zAxis()));
+			float distAlongViewDir = Math::abs(diff.dot(tfrm.getRotation().zAxis()));
 
 			return distAlongViewDir * mDefaultHandleSize;
 		}

+ 4 - 2
Source/BansheeEditor/Handles/BsHandleSlider.cpp

@@ -104,9 +104,11 @@ namespace bs
 		// position + direction can sometimes project behind the camera (if the camera is looking at position
 		// from very close and at an angle), which will cause the delta to be reversed, so we compensate.
 
+		const Transform& tfrm = camera->getTransform();
+
 		float negate = 1.0f;
-		Vector3 cameraDir = -camera->getRotation().zAxis();
-		if (cameraDir.dot((position + direction) - camera->getPosition()) <= 0.0f)
+		Vector3 cameraDir = -tfrm.getRotation().zAxis();
+		if (cameraDir.dot((position + direction) - tfrm.getPosition()) <= 0.0f)
 			negate = -1.0f; // Point behind the camera
 
 		Vector2I handleStart2D = camera->worldToScreenPoint(position);

+ 1 - 1
Source/BansheeEditor/Handles/BsHandleSliderPlane.cpp

@@ -76,7 +76,7 @@ namespace bs
 		Vector3 worldDir2 = getRotation().rotate(mDirection2);
 
 		Vector3 normal = worldDir1.cross(worldDir2);
-		float dot = normal.dot(camera->getForward());
+		float dot = normal.dot(camera->getTransform().getForward());
 		if (dot > 0)
 			normal = -normal;
 

+ 3 - 3
Source/BansheeEditor/SceneView/BsGizmoManager.cpp

@@ -460,7 +460,7 @@ namespace bs
 
 		IconRenderDataVecPtr iconRenderData;
 
-		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition());
+		mDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getTransform().getPosition());
 		mActiveMeshes = mDrawHelper->getMeshes();
 
 		Vector<MeshRenderData> proxyData = createMeshProxyData(mActiveMeshes);
@@ -652,7 +652,7 @@ namespace bs
 			iconData.back().color = idxToColorCallback(iconDataEntry.idx);
 		}
 
-		mPickingDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getPosition());
+		mPickingDrawHelper->buildMeshes(DrawHelper::SortType::BackToFront, camera->getTransform().getPosition());
 		const Vector<DrawHelper::ShapeMeshData>& meshes = mPickingDrawHelper->getMeshes();
 
 		SPtr<TransientMesh> iconMesh = buildIconMesh(camera, iconData, true, iconRenderData);
@@ -1055,7 +1055,7 @@ namespace bs
 		if (!usePickingMaterial)
 		{
 			gGizmoParamBlockDef.gMatViewProj.set(mMeshGizmoBuffer, viewProjMat);
-			gGizmoParamBlockDef.gViewDir.set(mMeshGizmoBuffer, (Vector4)camera->getForward());
+			gGizmoParamBlockDef.gViewDir.set(mMeshGizmoBuffer, (Vector4)camera->getTransform().getForward());
 
 			for (auto& entry : meshes)
 			{

+ 1 - 1
Source/BansheeEditor/SceneView/BsSceneGrid.cpp

@@ -219,7 +219,7 @@ namespace bs
 		Matrix4 viewProjMatrix = projMatrix * viewMatrix;
 		mViewProjParam.set(viewProjMatrix);
 
-		mWorldCameraPosParam.set(Vector4(mCamera->getPosition(), 1.0f));
+		mWorldCameraPosParam.set(Vector4(mCamera->getTransform().getPosition(), 1.0f));
 		mGridColorParam.set(GRID_LINE_COLOR);
 		mGridSpacingParam.set(mSpacing);
 		mGridBorderWidthParam.set(LINE_BORDER_WIDTH);

+ 5 - 9
Source/BansheeEditor/SceneView/BsScenePicking.cpp

@@ -61,7 +61,7 @@ namespace bs
 		if (data != nullptr)
 		{
 			Matrix3 rotation;
-			selectedObjects[0]->getWorldRotation().toRotationMatrix(rotation);
+			selectedObjects[0]->getTransform().getRotation().toRotationMatrix(rotation);
 			data->normal = rotation.inverse().transpose().transform(data->normal);
 		}
 		
@@ -87,17 +87,13 @@ namespace bs
 
 		Matrix4 viewProjMatrix = cam->getProjectionMatrixRS() * cam->getViewMatrix();
 
-		const Map<Renderable*, SceneRenderableData>& renderables = SceneManager::instance().getAllRenderables();
+		Vector<HRenderable> renderables = gSceneManager().findComponents<CRenderable>(true);
 		RenderableSet pickData(comparePickElement);
 		Map<UINT32, HSceneObject> idxToRenderable;
 
-		for (auto& renderableData : renderables)
+		for (auto& renderable : renderables)
 		{
-			SPtr<Renderable> renderable = renderableData.second.renderable;
-			HSceneObject so = renderableData.second.sceneObject;
-
-			if (!so->getActive())
-				continue;
+			HSceneObject so = renderable->SO();
 
 			HMesh mesh = renderable->getMesh();
 			if (!mesh.isLoaded())
@@ -117,7 +113,7 @@ namespace bs
 				continue;
 
 			Bounds worldBounds = mesh->getProperties().getBounds();
-			Matrix4 worldTransform = so->getWorldTfrm();
+			Matrix4 worldTransform = so->getWorldMatrix();
 			worldBounds.transformAffine(worldTransform);
 
 			const ConvexVolume& frustum = cam->getWorldFrustum();

+ 6 - 8
Source/BansheeEditor/SceneView/BsSelectionRenderer.cpp

@@ -43,20 +43,18 @@ namespace bs
 		Vector<SPtr<ct::Renderable>> objects;
 
 		const Vector<HSceneObject>& sceneObjects = Selection::instance().getSceneObjects();
-		const Map<Renderable*, SceneRenderableData>& renderables = SceneManager::instance().getAllRenderables();
+		Vector<HRenderable> renderables = gSceneManager().findComponents<CRenderable>(true);
 
 		for (auto& renderable : renderables)
 		{
+			HSceneObject renderableSO = renderable->SO();
 			for (auto& so : sceneObjects)
 			{
-				if (!so->getActive())
+				if (renderableSO != so)
 					continue;
 
-				if (renderable.second.sceneObject != so)
-					continue;
-
-				if (renderable.first->getMesh().isLoaded())
-					objects.push_back(renderable.first->getCore());
+				if (renderable->getMesh().isLoaded())
+					objects.push_back(renderable->_getRenderable()->getCore());
 			}
 		}
 
@@ -147,7 +145,7 @@ namespace bs
 			SPtr<VertexBuffer> morphShapeBuffer = renderable->getMorphShapeBuffer();
 			SPtr<VertexDeclaration> morphVertexDeclaration = renderable->getMorphVertexDeclaration();
 
-			Matrix4 worldViewProjMat = viewProjMat * renderable->getTransform();
+			Matrix4 worldViewProjMat = viewProjMat * renderable->getMatrix();
 			UINT32 techniqueIdx = mTechniqueIndices[(int)renderable->getAnimType()];
 
 			mMatWorldViewProj[techniqueIdx].set(worldViewProjMat);

+ 3 - 3
Source/BansheeEditor/Utility/BsEditorUtility.cpp

@@ -38,7 +38,7 @@ namespace bs
 				if (object.isDestroyed())
 					continue;
 
-				bounds.merge(object->getWorldPosition());
+				bounds.merge(object->getTransform().getPosition());
 				gotOneMesh = true;
 			}
 		}
@@ -63,7 +63,7 @@ namespace bs
 			if (calculateMeshBounds(object, meshBounds))
 			{
 				if (meshBounds.getSize() == Vector3::INF)
-					center += object->getWorldPosition();
+					center += object->getTransform().getPosition();
 				else
 					center += meshBounds.getCenter();
 
@@ -78,7 +78,7 @@ namespace bs
 				if (object.isDestroyed())
 					continue;
 
-				center += object->getWorldPosition();
+				center += object->getTransform().getPosition();
 				count++;
 			}
 		}

+ 3 - 1
Source/BansheeEngine/BsApplication.cpp

@@ -40,7 +40,6 @@ namespace bs
 
 		Cursor::shutDown();
 
-		ShortcutManager::shutDown();
 		GUIManager::shutDown();
 		SpriteManager::shutDown();
 		BuiltinResources::shutDown();
@@ -82,6 +81,9 @@ namespace bs
 		// could have allocated parts or all of those objects.
 		SceneManager::instance().clearScene(true);
 
+		// Shut down before script manager as scripts could have registered shortcut callbacks
+		ShortcutManager::shutDown();
+
 		ScriptManager::shutDown();
 		DebugDraw::shutDown();
 

+ 1 - 1
Source/BansheeEngine/Debug/BsDebugDraw.cpp

@@ -231,7 +231,7 @@ namespace bs
 		Matrix4 viewProjMat = projMatrix * viewMatrix;
 
 		gDebugDrawParamsDef.gMatViewProj.set(mParamBuffer, viewProjMat);
-		gDebugDrawParamsDef.gViewDir.set(mParamBuffer, (Vector4)camera.getForward());
+		gDebugDrawParamsDef.gViewDir.set(mParamBuffer, (Vector4)camera.getTransform().getForward());
 
 		for (auto& entry : mMeshes)
 		{

+ 5 - 4
Source/BansheeEngine/GUI/BsGUIWidget.cpp

@@ -104,9 +104,10 @@ namespace bs
 		// as the GUIManager batching relies on object positions, so it needs to be updated.
 		const float diffEpsilon = 0.0001f;
 
-		Vector3 position = parent->getWorldPosition();
-		Quaternion rotation = parent->getWorldRotation();
-		Vector3 scale = parent->getWorldScale();
+		const Transform& tfrm = parent->getTransform();
+		Vector3 position = tfrm.getPosition();
+		Quaternion rotation = tfrm.getRotation();
+		Vector3 scale = tfrm.getScale();
 
 		if(!mWidgetIsDirty)
 		{
@@ -127,7 +128,7 @@ namespace bs
 		mPosition = position;
 		mRotation = rotation;
 		mScale = scale;
-		mTransform = parent->getWorldTfrm();
+		mTransform = parent->getWorldMatrix();
 	}
 
 	void GUIWidget::_updateRT()

+ 4 - 0
Source/BansheeMono/BsMonoManager.cpp

@@ -139,6 +139,10 @@ namespace bs
 			mono_jit_cleanup(mRootDomain);
 			mRootDomain = nullptr;
 		}
+
+		// Make sure to explicitly clear this meta-data, as it contains structures allocated from other dynamic libraries,
+		// which will likely get unloaded right after shutdown
+		getScriptMetaData().clear();
 	}
 
 	MonoAssembly& MonoManager::loadAssembly(const WString& path, const String& name)

+ 4 - 2
Source/BansheePhysX/BsPhysXRigidbody.cpp

@@ -45,9 +45,11 @@ namespace bs
 	PhysXRigidbody::PhysXRigidbody(PxPhysics* physx, PxScene* scene, const HSceneObject& linkedSO)
 		:Rigidbody(linkedSO)
 	{
-		PxTransform tfrm = toPxTransform(linkedSO->getWorldPosition(), linkedSO->getWorldRotation());
 
-		mInternal = physx->createRigidDynamic(tfrm);
+		const Transform& tfrm = linkedSO->getTransform();
+		PxTransform pxTfrm = toPxTransform(tfrm.getPosition(), tfrm.getRotation());
+
+		mInternal = physx->createRigidDynamic(pxTfrm);
 		mInternal->userData = this;
 
 		scene->addActor(*mInternal);

+ 1 - 1
Source/BansheeUtility/FileSystem/BsPath.cpp

@@ -539,7 +539,7 @@ namespace bs
 
 	void Path::setDevice(const WString& device)
 	{
-		mNode = UTF8::fromWide(device);
+		mDevice = UTF8::fromWide(device);
 	}
 
 	String Path::buildWindows() const

File diff suppressed because it is too large
+ 538 - 538
Source/BansheeUtility/Math/BsMatrix3.cpp


+ 15 - 15
Source/BansheeUtility/Utility/BsDynLibManager.cpp

@@ -9,8 +9,8 @@ namespace bs
 	{
 	}
 
-    DynLib* DynLibManager::load(const String& name)
-    {
+	DynLib* DynLibManager::load(const String& name)
+	{
 		// Add the extension (.dll, .so, ...) if necessary.
 		String filename = name;
 		const UINT32 length = (UINT32)filename.length();
@@ -29,12 +29,12 @@ namespace bs
 		}
 		else
 		{
-	        DynLib* newLib = new (bs_alloc<DynLib>()) DynLib(filename);
-        	mLoadedLibraries[filename] = newLib;
+			DynLib* newLib = new (bs_alloc<DynLib>()) DynLib(filename);
+			mLoadedLibraries[filename] = newLib;
 
-	        return newLib;
+			return newLib;
 		}
-    }
+	}
 
 	void DynLibManager::unload(DynLib* lib)
 	{
@@ -49,17 +49,17 @@ namespace bs
 	}
 
 	DynLibManager::~DynLibManager()
-    {
-        // Unload & delete resources in turn
-        for(auto& entry : mLoadedLibraries)
-        {
-            entry.second->unload();
+	{
+		// Unload & delete resources in turn
+		for(auto& entry : mLoadedLibraries)
+		{
+			entry.second->unload();
 			bs_delete(entry.second);
-        }
+		}
 
-        // Empty the list
-        mLoadedLibraries.clear();
-    }
+		// Empty the list
+		mLoadedLibraries.clear();
+	}
 
 	DynLibManager& gDynLibManager()
 	{

+ 6 - 4
Source/Examples/ExampleGettingStarted/CameraFlyer.cpp

@@ -93,12 +93,14 @@ namespace bs
 			SO()->setRotation(camRot);
 		}
 
+		const Transform& tfrm = SO()->getTransform();
+
 		// If the movement button is pressed, determine direction to move in
 		Vector3 direction = Vector3::ZERO;
-		if (goingForward) direction += SO()->getForward();
-		if (goingBack) direction -= SO()->getForward();
-		if (goingRight) direction += SO()->getRight();
-		if (goingLeft) direction -= SO()->getRight();
+		if (goingForward) direction += tfrm.getForward();
+		if (goingBack) direction -= tfrm.getForward();
+		if (goingRight) direction += tfrm.getRight();
+		if (goingLeft) direction -= tfrm.getRight();
 
 		// If a direction is chosen, normalize it to determine final direction.
 		if (direction.squaredLength() != 0)

+ 6 - 4
Source/Examples/ExamplePhysicallyBasedShading/CameraFlyer.cpp

@@ -89,12 +89,14 @@ namespace bs
 			SO()->setRotation(camRot);
 		}
 
+		const Transform& tfrm = SO()->getTransform();
+
 		// If the movement button is pressed, determine direction to move in
 		Vector3 direction = Vector3::ZERO;
-		if (goingForward) direction += SO()->getForward();
-		if (goingBack) direction -= SO()->getForward();
-		if (goingRight) direction += SO()->getRight();
-		if (goingLeft) direction -= SO()->getRight();
+		if (goingForward) direction += tfrm.getForward();
+		if (goingBack) direction -= tfrm.getForward();
+		if (goingRight) direction += tfrm.getRight();
+		if (goingLeft) direction -= tfrm.getRight();
 
 		// If a direction is chosen, normalize it to determine final direction.
 		if (direction.squaredLength() != 0)

+ 3 - 2
Source/RenderBeast/BsImageBasedLighting.cpp

@@ -90,7 +90,8 @@ namespace bs { namespace ct
 		output.type = probe->getType() == ReflectionProbeType::Sphere ? 0 
 			: probe->getType() == ReflectionProbeType::Box ? 1 : 2;
 		
-		output.position = probe->getPosition();
+		const Transform& tfrm = probe->getTransform();
+		output.position = tfrm.getPosition();
 		output.boxExtents = probe->getExtents();
 
 		if (probe->getType() == ReflectionProbeType::Sphere)
@@ -100,7 +101,7 @@ namespace bs { namespace ct
 
 		output.transitionDistance = probe->getTransitionDistance();
 		output.cubemapIdx = arrayIdx;
-		output.invBoxTransform.setInverseTRS(output.position, probe->getRotation(), output.boxExtents);
+		output.invBoxTransform.setInverseTRS(output.position, tfrm.getRotation(), output.boxExtents);
 	}
 
 	void ImageBasedLightingParams::populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, 

+ 3 - 2
Source/RenderBeast/BsLightProbes.cpp

@@ -366,8 +366,9 @@ namespace bs { namespace ct
 			if (numProbes == 0)
 				continue;
 
-			Vector3 offset = entry.volume->getPosition();
-			Quaternion rotation = entry.volume->getRotation();
+			const Transform& tfrm = entry.volume->getTransform();
+			Vector3 offset = tfrm.getPosition();
+			Quaternion rotation = tfrm.getRotation();
 			for(UINT32 i = 0; i < numProbes; i++)
 			{
 				Vector3 localPos = positions[i];

+ 10 - 6
Source/RenderBeast/BsLightRendering.cpp

@@ -27,10 +27,11 @@ namespace bs { namespace ct
 		Radian spotFalloffAngle = Math::clamp(internal->getSpotFalloffAngle() * 0.5f, Degree(0), (Degree)spotAngle);
 		Color color = internal->getColor();
 
-		output.position = internal->getPosition();
+		const Transform& tfrm = internal->getTransform();
+		output.position = tfrm.getPosition();
 		output.attRadius = internal->getBounds().getRadius();
 		output.srcRadius = internal->getSourceRadius();
-		output.direction = -internal->getRotation().zAxis();
+		output.direction = -tfrm.getRotation().zAxis();
 		output.luminance = internal->getLuminance();
 		output.spotAngles.x = spotAngle.valueRadians();
 		output.spotAngles.y = Math::cos(output.spotAngles.x);
@@ -83,8 +84,10 @@ namespace bs { namespace ct
 
 		gPerLightParamDef.gLightGeometry.set(buffer, lightGeometry);
 
+		const Transform& tfrm = internal->getTransform();
+
 		Quaternion lightRotation(BsIdentity);
-		lightRotation.lookRotation(-internal->getRotation().zAxis());
+		lightRotation.lookRotation(-tfrm.getRotation().zAxis());
 
 		Matrix4 transform = Matrix4::TRS(lightData.shiftedLightPosition, lightRotation, Vector3::ONE);
 		gPerLightParamDef.gMatConeTransform.set(buffer, transform);
@@ -92,13 +95,14 @@ namespace bs { namespace ct
 
 	Vector3 RendererLight::getShiftedLightPosition() const
 	{
-		Vector3 direction = -internal->getRotation().zAxis();
+		const Transform& tfrm = internal->getTransform();
+		Vector3 direction = -tfrm.getRotation().zAxis();
 
 		// Create position for fake attenuation for area spot lights (with disc center)
 		if (internal->getType() == LightType::Spot)
-			return internal->getPosition() - direction * (internal->getSourceRadius() / Math::tan(internal->getSpotAngle() * 0.5f));
+			return tfrm.getPosition() - direction * (internal->getSourceRadius() / Math::tan(internal->getSpotAngle() * 0.5f));
 		else
-			return internal->getPosition();
+			return tfrm.getPosition();
 	}
 
 	GBufferParams::GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet)

+ 3 - 3
Source/RenderBeast/BsRendererObject.cpp

@@ -15,8 +15,8 @@ namespace bs { namespace ct
 
 	void RendererObject::updatePerObjectBuffer()
 	{
-		Matrix4 worldTransform = renderable->getTransform();
-		Matrix4 worldNoScaleTransform = renderable->getTransformNoScale();
+		Matrix4 worldTransform = renderable->getMatrix();
+		Matrix4 worldNoScaleTransform = renderable->getMatrixNoScale();
 
 		gPerObjectParamDef.gMatWorld.set(perObjectParamBuffer, worldTransform);
 		gPerObjectParamDef.gMatInvWorld.set(perObjectParamBuffer, worldTransform.inverseAffine());
@@ -27,7 +27,7 @@ namespace bs { namespace ct
 
 	void RendererObject::updatePerCallBuffer(const Matrix4& viewProj, bool flush)
 	{
-		Matrix4 worldViewProjMatrix = viewProj * renderable->getTransform();
+		Matrix4 worldViewProjMatrix = viewProj * renderable->getMatrix();
 
 		gPerCallParamDef.gMatWorldViewProj.set(perCallParamBuffer, worldViewProjMatrix);
 

+ 7 - 5
Source/RenderBeast/BsRendererScene.cpp

@@ -52,7 +52,7 @@ namespace bs {	namespace ct
 		UINT32 cameraId = camera->getRendererId();
 		RendererView* view = mInfo.views[cameraId];
 
-		if((updateFlag & (UINT32)CameraDirtyFlag::Everything) != 0)
+		if((updateFlag & ((UINT32)ActorDirtyFlag::Everything | (UINT32)ActorDirtyFlag::Active)) != 0)
 		{
 			RENDERER_VIEW_DESC viewDesc = createViewDesc(camera);
 
@@ -69,9 +69,10 @@ namespace bs {	namespace ct
 		{
 			view = mInfo.views[cameraId];
 
+			const Transform& tfrm = camera->getTransform();
 			view->setTransform(
-				camera->getPosition(),
-				camera->getForward(),
+				tfrm.getPosition(),
+				tfrm.getForward(),
 				camera->getViewMatrix(),
 				camera->getProjectionMatrixRS(),
 				camera->getWorldFrustum());
@@ -556,8 +557,9 @@ namespace bs {	namespace ct
 		viewDesc.farPlane = camera->getFarClipDistance();
 		viewDesc.flipView = false;
 
-		viewDesc.viewOrigin = camera->getPosition();
-		viewDesc.viewDirection = camera->getForward();
+		const Transform& tfrm = camera->getTransform();
+		viewDesc.viewOrigin = tfrm.getPosition();
+		viewDesc.viewDirection = tfrm.getForward();
 		viewDesc.projTransform = camera->getProjectionMatrixRS();
 		viewDesc.viewTransform = camera->getViewMatrix();
 		viewDesc.projType = camera->getProjectionType();

+ 12 - 10
Source/RenderBeast/BsShadowRendering.cpp

@@ -351,7 +351,7 @@ namespace bs { namespace ct
 
 	void ShadowProjectOmniMat::bind(const ShadowProjectParams& params)
 	{
-		Vector4 lightPosAndScale(params.light.getPosition(), params.light.getAttenuationRadius());
+		Vector4 lightPosAndScale(params.light.getTransform().getPosition(), params.light.getAttenuationRadius());
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
 
 		mGBufferParams.bind(params.gbuffer);
@@ -850,7 +850,8 @@ namespace bs { namespace ct
 				gShadowProjectOmniParamsDef.gFadePercent.set(shadowOmniParamBuffer, shadowInfo.fadePerView[viewIdx]);
 				gShadowProjectOmniParamsDef.gInvResolution.set(shadowOmniParamBuffer, 1.0f / shadowInfo.area.width);
 
-				Vector4 lightPosAndRadius(light->getPosition(), light->getAttenuationRadius());
+				const Transform& tfrm = light->getTransform();
+				Vector4 lightPosAndRadius(tfrm.getPosition(), light->getAttenuationRadius());
 				gShadowProjectOmniParamsDef.gLightPosAndRadius.set(shadowOmniParamBuffer, lightPosAndRadius);
 
 				// Reduce shadow quality based on shadow map resolution for spot lights
@@ -859,7 +860,7 @@ namespace bs { namespace ct
 				// Check if viewer is inside the light bounds
 				//// Expand the light bounds slightly to handle the case when the near plane is intersecting the light volume
 				float lightRadius = light->getAttenuationRadius() + viewProps.nearPlane * 3.0f;
-				bool viewerInsideVolume = (light->getPosition() - viewProps.viewOrigin).length() < lightRadius;
+				bool viewerInsideVolume = (tfrm.getPosition() - viewProps.viewOrigin).length() < lightRadius;
 
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
 				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowOmniParamBuffer, perViewBuffer, gbuffer);
@@ -1027,7 +1028,8 @@ namespace bs { namespace ct
 
 		RenderAPI& rapi = RenderAPI::instance();
 
-		Vector3 lightDir = -light->getRotation().zAxis();
+		const Transform& tfrm = light->getTransform();
+		Vector3 lightDir = -tfrm.getRotation().zAxis();
 		SPtr<GpuParamBlockBuffer> shadowParamsBuffer = gShadowParamsDef.createBuffer();
 
 		ShadowInfo shadowInfo;
@@ -1063,9 +1065,9 @@ namespace bs { namespace ct
 		ShadowCascadedMap& shadowMap = mCascadedShadowMaps[shadowInfo.textureIdx];
 
 		Quaternion lightRotation(BsIdentity);
-		lightRotation.lookRotation(-light->getRotation().zAxis());
+		lightRotation.lookRotation(-tfrm.getRotation().zAxis());
 
-		Matrix4 viewMat = Matrix4::view(light->getPosition(), lightRotation);
+		Matrix4 viewMat = Matrix4::view(tfrm.getPosition(), lightRotation);
 		for (UINT32 i = 0; i < NUM_CASCADE_SPLITS; ++i)
 		{
 			Sphere frustumBounds;
@@ -1078,7 +1080,7 @@ namespace bs { namespace ct
 
 			shadowInfo.depthRange = maxSubjectDepth - minSubjectDepth;
 
-			Vector3 offsetLightPos = light->getPosition() + lightDir * minSubjectDepth;
+			Vector3 offsetLightPos = tfrm.getPosition() + lightDir * minSubjectDepth;
 			Matrix4 offsetViewMat = Matrix4::view(offsetLightPos, lightRotation);
 
 			float orthoSize = frustumBounds.getRadius() * 0.5f;
@@ -1197,7 +1199,7 @@ namespace bs { namespace ct
 		mapInfo.subjectBounds = light->getBounds();
 
 		Quaternion lightRotation(BsIdentity);
-		lightRotation.lookRotation(-light->getRotation().zAxis());
+		lightRotation.lookRotation(-light->getTransform().getRotation().zAxis());
 
 		Matrix4 view = Matrix4::view(rendererLight.getShiftedLightPosition(), lightRotation);
 		Matrix4 proj = Matrix4::projectionPerspective(light->getSpotAngle(), 1.0f, 0.05f, light->getAttenuationRadius());
@@ -1332,7 +1334,7 @@ namespace bs { namespace ct
 		gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, Matrix4::IDENTITY);
 		gShadowParamsDef.gNDCZToDeviceZ.set(shadowParamsBuffer, RendererView::getNDCZToDeviceZ());
 
-		Matrix4 viewOffsetMat = Matrix4::translation(-light->getPosition());
+		Matrix4 viewOffsetMat = Matrix4::translation(-light->getTransform().getPosition());
 
 		ConvexVolume frustums[6];
 		Vector<Plane> boundingPlanes;
@@ -1455,7 +1457,7 @@ namespace bs { namespace ct
 				// largest one
 				//// First get sphere depth
 				const Matrix4& viewVP = viewProps.viewProjTransform;
-				float depth = viewVP.multiply(Vector4(light.internal->getPosition(), 1.0f)).w;
+				float depth = viewVP.multiply(Vector4(light.internal->getTransform().getPosition(), 1.0f)).w;
 
 				// This is just 1/tan(fov), for both horz. and vert. FOV
 				float viewScaleX = viewProps.projTransform[0][0];

+ 5 - 3
Source/SBansheeEngine/Wrappers/BsScriptScene.cpp

@@ -10,6 +10,7 @@
 #include "Scene/BsPrefab.h"
 #include "BsApplication.h"
 #include "Scene/BsSceneObject.h"
+#include "Renderer/BsCamera.h"
 #include "BsScriptGameObjectManager.h"
 #include "Resources/BsGameResourceManager.h"
 #include "BsScriptResourceManager.h"
@@ -137,11 +138,12 @@ namespace bs
 
 	MonoObject* ScriptScene::internal_GetMainCameraSO()
 	{
-		SceneCameraData cameraData = gSceneManager().getMainCamera();
-		if (cameraData.sceneObject == nullptr)
+		SPtr<Camera> camera = gSceneManager().getMainCamera();
+		HSceneObject so = gSceneManager()._getActorSO(camera);
+		if (so == nullptr)
 			return nullptr;
 
-		ScriptSceneObject* cameraSo = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(cameraData.sceneObject);
+		ScriptSceneObject* cameraSo = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(so);
 		return cameraSo->getManagedInstance();
 	}
 }

+ 11 - 11
Source/SBansheeEngine/Wrappers/BsScriptSceneObject.cpp

@@ -216,7 +216,7 @@ namespace bs
 	void ScriptSceneObject::internal_getPosition(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getWorldPosition();
+			*value = nativeInstance->mSceneObject->getTransform().getPosition();
 		else
 			*value = Vector3(BsZero);
 	}
@@ -224,7 +224,7 @@ namespace bs
 	void ScriptSceneObject::internal_getLocalPosition(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getPosition();
+			*value = nativeInstance->mSceneObject->getLocalTransform().getPosition();
 		else
 			*value = Vector3(BsZero);
 	}
@@ -232,7 +232,7 @@ namespace bs
 	void ScriptSceneObject::internal_getRotation(ScriptSceneObject* nativeInstance, Quaternion* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getWorldRotation();
+			*value = nativeInstance->mSceneObject->getTransform().getRotation();
 		else
 			*value = Quaternion(BsIdentity);
 	}
@@ -240,7 +240,7 @@ namespace bs
 	void ScriptSceneObject::internal_getLocalRotation(ScriptSceneObject* nativeInstance, Quaternion* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getRotation();
+			*value = nativeInstance->mSceneObject->getLocalTransform().getRotation();
 		else
 			*value = Quaternion(BsIdentity);
 	}
@@ -248,7 +248,7 @@ namespace bs
 	void ScriptSceneObject::internal_getScale(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getWorldScale();
+			*value = nativeInstance->mSceneObject->getTransform().getScale();
 		else
 			*value = Vector3(Vector3::ONE);
 	}
@@ -256,7 +256,7 @@ namespace bs
 	void ScriptSceneObject::internal_getLocalScale(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getScale();
+			*value = nativeInstance->mSceneObject->getLocalTransform().getScale();
 		else
 			*value = Vector3(Vector3::ONE);
 	}
@@ -294,7 +294,7 @@ namespace bs
 	void ScriptSceneObject::internal_getLocalTransform(ScriptSceneObject* nativeInstance, Matrix4* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getLocalTfrm();
+			*value = nativeInstance->mSceneObject->getLocalMatrix();
 		else
 			*value = Matrix4();
 	}
@@ -302,7 +302,7 @@ namespace bs
 	void ScriptSceneObject::internal_getWorldTransform(ScriptSceneObject* nativeInstance, Matrix4* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getWorldTfrm();
+			*value = nativeInstance->mSceneObject->getWorldMatrix();
 		else
 			*value = Matrix4();
 	}
@@ -358,7 +358,7 @@ namespace bs
 	void ScriptSceneObject::internal_getForward(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getForward();
+			*value = nativeInstance->mSceneObject->getTransform().getForward();
 		else
 			*value = Vector3(-Vector3::UNIT_Z);
 	}
@@ -366,7 +366,7 @@ namespace bs
 	void ScriptSceneObject::internal_getUp(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getUp();
+			*value = nativeInstance->mSceneObject->getTransform().getUp();
 		else
 			*value = Vector3(Vector3::UNIT_Y);
 	}
@@ -374,7 +374,7 @@ namespace bs
 	void ScriptSceneObject::internal_getRight(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))
-			*value = nativeInstance->mSceneObject->getRight();
+			*value = nativeInstance->mSceneObject->getTransform().getRight();
 		else
 			*value = Vector3(Vector3::UNIT_X);
 	}

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUI.cpp

@@ -26,7 +26,7 @@ namespace bs
 
 	void ScriptGUI::startUp()
 	{
-		SPtr<Camera> mainCamera = gSceneManager().getMainCamera().camera;
+		SPtr<Camera> mainCamera = gSceneManager().getMainCamera();
 		sGUIWidget = GUIWidget::create(mainCamera);
 		sGUIWidget->setSkin(BuiltinResources::instance().getGUISkin());
 
@@ -59,7 +59,7 @@ namespace bs
 		if (sGUIWidget == nullptr)
 			return;
 
-		SPtr<Camera> mainCamera = gSceneManager().getMainCamera().camera;
+		SPtr<Camera> mainCamera = gSceneManager().getMainCamera();
 		if (mainCamera != sGUIWidget->getCamera())
 			sGUIWidget->setCamera(mainCamera);
 

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIWidget.cpp

@@ -19,7 +19,7 @@ namespace bs
 	ScriptGUIWidget::ScriptGUIWidget(MonoObject* managedInstance)
 		:ScriptObject(managedInstance), mGUIWidget(nullptr), mLastUpdateHash((UINT32)-1)
 	{
-		SPtr<Camera> mainCamera = gSceneManager().getMainCamera().camera;
+		SPtr<Camera> mainCamera = gSceneManager().getMainCamera();
 
 		mGUIWidget = GUIWidget::create(mainCamera);
 		mGUIWidget->setSkin(BuiltinResources::instance().getGUISkin());
@@ -102,7 +102,7 @@ namespace bs
 			nativeCamera = camera->getHandle()->_getCamera();
 
 		if(nativeCamera == nullptr)
-			nativeCamera = gSceneManager().getMainCamera().camera;
+			nativeCamera = gSceneManager().getMainCamera();
 
 		SPtr<GUIWidget> widget = instance->getInternal();
 		if(widget != nullptr)

Some files were not shown because too many files changed in this diff