Jelajahi Sumber

Refactored camera into CameraHandler

Marko Pintera 11 tahun lalu
induk
melakukan
cade69ad2c

+ 10 - 0
BansheeCore/Include/BsSceneObject.h

@@ -234,6 +234,14 @@ namespace BansheeEngine
 		 */
 		 */
 		void _markCoreClean() { mIsCoreDirtyFlags = 0; }
 		void _markCoreClean() { mIsCoreDirtyFlags = 0; }
 
 
+		/**
+		 * @brief	Returns a hash value that changes whenever a scene objects
+		 *			transform gets updated. It allows you to detect changes with
+		 *			the local or world transforms without directly comparing their
+		 *			values with some older state.
+		 */
+		UINT32 getTransformHash() const { return mDirtyHash; }
+
 	private:
 	private:
 		Vector3 mPosition;
 		Vector3 mPosition;
 		Quaternion mRotation;
 		Quaternion mRotation;
@@ -249,6 +257,8 @@ namespace BansheeEngine
 		mutable UINT32 mDirtyFlags;
 		mutable UINT32 mDirtyFlags;
 		mutable UINT32 mIsCoreDirtyFlags;
 		mutable UINT32 mIsCoreDirtyFlags;
 
 
+		mutable UINT32 mDirtyHash;
+
 		/**
 		/**
 		 * @brief	Marks the transform as dirty so that we know to update
 		 * @brief	Marks the transform as dirty so that we know to update
 		 *			it when the transform is requested.
 		 *			it when the transform is requested.

+ 2 - 1
BansheeCore/Source/BsSceneObject.cpp

@@ -13,7 +13,7 @@ namespace BansheeEngine
 		:GameObject(), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::ONE),
 		:GameObject(), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::ONE),
 		mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY), mWorldScale(Vector3::ONE),
 		mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY), mWorldScale(Vector3::ONE),
 		mCachedLocalTfrm(Matrix4::IDENTITY), mDirtyFlags(0xFFFFFFFF), mCachedWorldTfrm(Matrix4::IDENTITY), 
 		mCachedLocalTfrm(Matrix4::IDENTITY), mDirtyFlags(0xFFFFFFFF), mCachedWorldTfrm(Matrix4::IDENTITY), 
-		mIsCoreDirtyFlags(0xFFFFFFFF), mActiveSelf(true), mActiveHierarchy(true)
+		mIsCoreDirtyFlags(0xFFFFFFFF), mActiveSelf(true), mActiveHierarchy(true), mDirtyHash(0)
 	{
 	{
 		setName(name);
 		setName(name);
 	}
 	}
@@ -283,6 +283,7 @@ namespace BansheeEngine
 	{
 	{
 		mDirtyFlags |= DirtyFlags::LocalTfrmDirty | DirtyFlags::WorldTfrmDirty;
 		mDirtyFlags |= DirtyFlags::LocalTfrmDirty | DirtyFlags::WorldTfrmDirty;
 		mIsCoreDirtyFlags = 0xFFFFFFFF;
 		mIsCoreDirtyFlags = 0xFFFFFFFF;
+		mDirtyHash++;
 
 
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 		{
 		{

+ 3 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -226,6 +226,7 @@
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClCompile Include="Source\BsCameraHandler.cpp" />
     <ClCompile Include="Source\BsCursor.cpp" />
     <ClCompile Include="Source\BsCursor.cpp" />
     <ClCompile Include="Source\BsDrawHelper.cpp" />
     <ClCompile Include="Source\BsDrawHelper.cpp" />
     <ClCompile Include="Source\BsGUILayoutUtility.cpp" />
     <ClCompile Include="Source\BsGUILayoutUtility.cpp" />
@@ -235,6 +236,8 @@
     <ClCompile Include="Source\BsRenderQueue.cpp" />
     <ClCompile Include="Source\BsRenderQueue.cpp" />
     <ClCompile Include="Source\BsVirtualInput.cpp" />
     <ClCompile Include="Source\BsVirtualInput.cpp" />
     <ClInclude Include="Include\BsApplication.h" />
     <ClInclude Include="Include\BsApplication.h" />
+    <ClInclude Include="Include\BsCameraHandler.h" />
+    <ClInclude Include="Include\BsCameraHandlerRTTI.h" />
     <ClInclude Include="Include\BsCursor.h" />
     <ClInclude Include="Include\BsCursor.h" />
     <ClInclude Include="Include\BsDrawHelper.h" />
     <ClInclude Include="Include\BsDrawHelper.h" />
     <ClInclude Include="Include\BsShapeMeshes3D.h" />
     <ClInclude Include="Include\BsShapeMeshes3D.h" />

+ 12 - 3
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -87,9 +87,6 @@
     <ClInclude Include="Include\BsOverlay.h">
     <ClInclude Include="Include\BsOverlay.h">
       <Filter>Header Files\Components</Filter>
       <Filter>Header Files\Components</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="Include\BsCamera.h">
-      <Filter>Header Files\Components</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsRenderable.h">
     <ClInclude Include="Include\BsRenderable.h">
       <Filter>Header Files\Components</Filter>
       <Filter>Header Files\Components</Filter>
     </ClInclude>
     </ClInclude>
@@ -273,6 +270,15 @@
     <ClInclude Include="Include\BsDrawHelper.h">
     <ClInclude Include="Include\BsDrawHelper.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsCamera.h">
+      <Filter>Header Files\Components</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsCameraHandler.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsCameraHandlerRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -470,5 +476,8 @@
     <ClCompile Include="Source\BsDrawHelper.cpp">
     <ClCompile Include="Source\BsDrawHelper.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsCameraHandler.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 146 - 307
BansheeEngine/Include/BsCamera.h

@@ -1,45 +1,14 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
-#include "BsMatrix4.h"
-#include "BsVector3.h"
-#include "BsVector2.h"
-#include "BsAABox.h"
-#include "BsVertexData.h"
-#include "BsPlane.h"
-#include "BsQuaternion.h"
-#include "BsRay.h"
+#include "BsCameraHandler.h"
 #include "BsComponent.h"
 #include "BsComponent.h"
-#include "BsCameraProxy.h"
-#include "BsConvexVolume.h"
+#include "BsViewport.h"
 
 
 namespace BansheeEngine 
 namespace BansheeEngine 
 {
 {
 	/**
 	/**
-	 * @brief	Specified projection type to use by the camera.
-	 */
-    enum ProjectionType
-    {
-        PT_ORTHOGRAPHIC,
-        PT_PERSPECTIVE
-    };
-
-	/**
-	 * @brief	Clip planes that form the camera frustum (visible area).
-	 */
-    enum FrustumPlane
-    {
-        FRUSTUM_PLANE_NEAR = 0,
-        FRUSTUM_PLANE_FAR = 1,
-        FRUSTUM_PLANE_LEFT = 2,
-        FRUSTUM_PLANE_RIGHT = 3,
-        FRUSTUM_PLANE_TOP = 4,
-        FRUSTUM_PLANE_BOTTOM = 5
-    };
-
-	/**
-	 * @brief	Camera determines how is world geometry projected onto a 2D surface. You may
-	 *			position and orient it in space, and set other options like aspect ratio and field or view.
+	 * @copydoc	CameraHandler
 	 */
 	 */
     class BS_EXPORT Camera : public Component
     class BS_EXPORT Camera : public Component
     {
     {
@@ -50,435 +19,305 @@ namespace BansheeEngine
         virtual ~Camera();
         virtual ~Camera();
 
 
 		/**
 		/**
-		 * @brief	Returns the viewport used by the camera.
-		 */	
-		ViewportPtr getViewport() const { return mViewport; }
+		 * @copydoc	CameraHandler::getViewport
+		 */
+		ViewportPtr getViewport() const { return mInternal.getViewport(); }
 
 
 		/**
 		/**
-		 * @brief	Sets 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.
+		 * @copydoc	CameraHandler::setHorzFOV
 		 */
 		 */
-        virtual void setHorzFOV(const Radian& fovy);
+		virtual void setHorzFOV(const Radian& fovy) { mInternal.setHorzFOV(fovy); }
 
 
 		/**
 		/**
-		 * @brief	Retrieves the camera horizontal field of view.
+		 * @copydoc	CameraHandler::getHorzFOV
 		 */
 		 */
-        virtual const Radian& getHorzFOV() const;
+		virtual const Radian& getHorzFOV() const { return mInternal.getHorzFOV(); }
 
 
 		/**
 		/**
-		 * @brief	Sets the distance from the frustum to the near clipping plane. Anything
-		 *			closer than the near clipping plane will not be rendered. Decreasing this value
-		 *			decreases depth buffer precision.
+		 * @copydoc	CameraHandler::setNearClipDistance
 		 */
 		 */
-        virtual void setNearClipDistance(float nearDist);
+		virtual void setNearClipDistance(float nearDist) { mInternal.setNearClipDistance(nearDist); }
 
 
 		/**
 		/**
-		 * @brief	Retrieves the distance from the frustum to the near clipping plane. Anything
-		 *			closer than the near clipping plane will not be rendered. Decreasing this value
-		 *			decreases depth buffer precision.
+		 * @copydoc	CameraHandler::getNearClipDistance
 		 */
 		 */
-        virtual float getNearClipDistance() const;
+		virtual float getNearClipDistance() const { return mInternal.getNearClipDistance(); }
 
 
 		/**
 		/**
-		 * @brief	Sets the distance from the frustum to the far clipping plane. Anything
-		 *			farther than the far clipping plane will not be rendered. Increasing this value
-		 *			decreases depth buffer precision.
+		 * @copydoc	CameraHandler::setFarClipDistance
 		 */
 		 */
-        virtual void setFarClipDistance(float farDist);
+		virtual void setFarClipDistance(float farDist) { mInternal.setFarClipDistance(farDist); }
 
 
 		/**
 		/**
-		 * @brief	Retrieves the distance from the frustum to the far clipping plane. Anything
-		 *			farther than the far clipping plane will not be rendered. Increasing this value
-		 *			decreases depth buffer precision.
+		 * @copydoc	CameraHandler::getFarClipDistance
 		 */
 		 */
-        virtual float getFarClipDistance() const;
+		virtual float getFarClipDistance() const { return mInternal.getFarClipDistance(); }
 
 
 		/**
 		/**
-		 * @brief	Sets the current viewport aspect ratio (width / height).
+		 * @copydoc	CameraHandler::setAspectRatio
 		 */
 		 */
-        virtual void setAspectRatio(float ratio);
+		virtual void setAspectRatio(float ratio) { mInternal.setAspectRatio(ratio); }
 
 
 		/**
 		/**
-		 * @brief	Returns current viewport aspect ratio (width / height).
+		 * @copydoc	CameraHandler::getAspectRatio
 		 */
 		 */
-        virtual float getAspectRatio() const;
-
-		/** @brief	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.
-		 *
-		 *	@param left		The position where the left clip plane intersect the near clip plane, in view space.
-		 *  @param right	The position where the right clip plane intersect the near clip plane, in view space.
-		 *  @param top		The position where the top clip plane intersect the near clip plane, in view space.
-		 *  @param bottom	The position where the bottom clip plane intersect the near clip plane, in view space.
-		*/
-		virtual void setFrustumExtents(float left, float right, float top, float bottom);
+		virtual float getAspectRatio() const { return mInternal.getAspectRatio(); }
 
 
-		/** 
-		 * @brief	Resets frustum extents so they are automatically derived from other values.
-		 *			This is only relevant if you have previously set custom extents.
+		/**
+		 * @copydoc	CameraHandler::setFrustumExtents
 		 */
 		 */
-		virtual void resetFrustumExtents(); 
+		virtual void setFrustumExtents(float left, float right, float top, float bottom)
+		{
+			mInternal.setFrustumExtents(left, right, top, bottom);
+		}
 
 
-		/** 
-		 * @brief	Returns the extents of the frustum in view space at the near plane.
+		/**
+		 * @copydoc	CameraHandler::resetFrustumExtents
 		 */
 		 */
-		virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const;
+		virtual void resetFrustumExtents() { mInternal.resetFrustumExtents(); }
 
 
-		/** 
-		 * @brief	Returns the standard projection matrix that determines how are 3D points
-		 *			projected to two dimensions. The layout of this matrix depends on currently
-		 *			used render system.
-		 *
-		 * @note	You should use this matrix when sending the matrix to the render system to remain
-		 *			everything works consistently when other render systems are used.
+		/**
+		 * @copydoc	CameraHandler::getFrustumExtents
 		 */
 		 */
-        virtual const Matrix4& getProjectionMatrixRS() const;
-
-		/** 
-		 * @brief	Returns the standard projection matrix that determines how are 3D points
-		 *			projected to two dimensions. Returned matrix is standard following right-hand
-		 *			rules and depth range of [-1, 1]. 
-		 *
-		 * @note	Different render systems will expect different projection matrix layouts, in which
-		 *			case use getProjectionMatrixRS.
-         */
-        virtual const Matrix4& getProjectionMatrix() const;
-
-		/** 
-		 * @brief	Gets the camera view matrix. Used for positioning/orienting the camera.
-         */
-        virtual const Matrix4& getViewMatrix() const;
-
-		/** 
-		 * @brief	Sets whether the camera should use the custom view matrix.
-		 *			When this is enabled camera will no longer calculate its view matrix
-		 *			based on position/orientation and caller will be resonsible to keep 
-		 *			the view matrix up to date.
-         */
-		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
-
-		/** 
-		 * @brief	Returns true if a custom view matrix is used.
-         */
-		virtual bool isCustomViewMatrixEnabled() const { return mCustomViewMatrix; }
-		
-		/** 
-		 * @brief	Sets whether the camera should use the custom projection matrix.
-		 *			When this is enabled camera will no longer calculate its projection matrix
-		 *			based on field of view, aspect and other parameters and caller will be
-		 *			resonsible to keep the projection matrix up to date.
-         */
-		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
-
-		/** 
-		 * @brief	Returns true if a custom projection matrix is used.
-         */
-		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
-
-		/** 
-		 * @brief	Returns a convex volume representing the visible area of the camera,
-		 *			in local space.
-         */
-        virtual const ConvexVolume& getFrustum() const;
-
-		/** 
-		 * @brief	Returns a convex volume representing the visible area of the camera,
-		 *			in world space.
-         */
-        virtual ConvexVolume getWorldFrustum() const;
+		virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
+		{
+			mInternal.getFrustumExtents(outleft, outright, outtop, outbottom);
+		}
 
 
 		/**
 		/**
-		 * @brief	Returns the bounding of the frustum.
+		 * @copydoc	CameraHandler::getProjectionMatrixRS
 		 */
 		 */
-        const AABox& getBoundingBox() const;
+		virtual const Matrix4& getProjectionMatrixRS() const { return mInternal.getProjectionMatrixRS(); }
 
 
 		/**
 		/**
-		 * @brief	Sets the type of projection used by the camera.
+		 * @copydoc	CameraHandler::getProjectionMatrix
 		 */
 		 */
-        virtual void setProjectionType(ProjectionType pt);
+		virtual const Matrix4& getProjectionMatrix() const { return mInternal.getProjectionMatrix(); }
 
 
 		/**
 		/**
-		 * @brief	Returns the type of projection used by the camera.
+		 * @copydoc	CameraHandler::getViewMatrix
 		 */
 		 */
-        virtual ProjectionType getProjectionType() const;
+		virtual const Matrix4& getViewMatrix() const { updateView(); return mInternal.getViewMatrix(); }
 
 
 		/**
 		/**
-		 * @brief	Sets the orthographic window height, for use with orthographic rendering only. 
-		 *
-		 * @param	w	Width of the window in world units.
-		 * @param	h	Height of the window in world units.
-		 *
-		 * @note	Calling this method will recalculate the aspect ratio, use setOrthoWindowHeight or 
-		 *			setOrthoWindowWidth alone if you wish to preserve the aspect ratio but just fit one 
-		 *			or other dimension to a particular size.
+		 * @copydoc	CameraHandler::setCustomViewMatrix
 		 */
 		 */
-		virtual void setOrthoWindow(float w, float h);
+		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY)
+		{
+			mInternal.setCustomViewMatrix(enable, viewMatrix);
+		}
 
 
 		/**
 		/**
-		 * @brief	Sets the orthographic window height, for use with orthographic rendering only. 
-		 *
-		 * @param	h	Height of the window in world units.
-		 *
-		 * @note	The width of the window will be calculated from the aspect ratio. 
+		 * @copydoc	CameraHandler::isCustomViewMatrixEnabled
 		 */
 		 */
-		virtual void setOrthoWindowHeight(float h);
-
+		virtual bool isCustomViewMatrixEnabled() const { return mInternal.isCustomViewMatrixEnabled(); }
+		
 		/**
 		/**
-		 * @brief	Sets the orthographic window width, for use with orthographic rendering only. 
-		 *
-		 * @param	w	Width of the window in world units.
-		 *
-		 * @note	The height of the window will be calculated from the aspect ratio. 
+		 * @copydoc	CameraHandler::setCustomProjectionMatrix
 		 */
 		 */
-		virtual void setOrthoWindowWidth(float w);
+		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY)
+		{
+			mInternal.setCustomProjectionMatrix(enable, projectionMatrix);
+		}
 
 
 		/**
 		/**
-		 * @brief	Gets the orthographic window width in world units, for use with orthographic rendering only. 
+		 * @copydoc	CameraHandler::isCustomProjectionMatrixEnabled
 		 */
 		 */
-		virtual float getOrthoWindowHeight() const;
+		virtual bool isCustomProjectionMatrixEnabled() const { return mInternal.isCustomProjectionMatrixEnabled(); }
 
 
 		/**
 		/**
-		 * @brief	Gets the orthographic window width in world units, for use with orthographic rendering only. 
-		 *
-		 * @note	This is calculated from the orthographic height and the aspect ratio.
+		 * @copydoc	CameraHandler::getFrustum
 		 */
 		 */
-		virtual float getOrthoWindowWidth() const;
+		virtual const ConvexVolume& getFrustum() const { return mInternal.getFrustum(); }
 
 
 		/**
 		/**
-		 * @brief	This option tells the renderer that this camera should ignore any renderable components.
+		 * @copydoc	CameraHandler::getWorldFrustum
 		 */
 		 */
-		void setIgnoreSceneRenderables(bool value) { mIgnoreSceneRenderables = true; markCoreDirty(); }
+        virtual ConvexVolume getWorldFrustum() const;
 
 
 		/**
 		/**
-		 * @brief	This option tells the renderer that this camera should ignore any renderable components.
+		 * @copydoc	CameraHandler::getBoundingBox
 		 */
 		 */
-		bool getIgnoreSceneRenderables() const { return mIgnoreSceneRenderables; }
+		const AABox& getBoundingBox() const { return mInternal.getBoundingBox(); }
 
 
 		/**
 		/**
-		 * @brief	Gets a priority that determines in which orders the cameras are rendered.
-		 *			This only applies to cameras rendering to the same render target. 
+		 * @copydoc	CameraHandler::setProjectionType
 		 */
 		 */
-		INT32 getPriority() const { return mPriority; }
+		virtual void setProjectionType(ProjectionType pt) { mInternal.setProjectionType(pt); }
 
 
 		/**
 		/**
-		 * @brief	Sets a priority that determines in which orders the cameras are rendered.
-		 * 			This only applies to cameras rendering to the same render target. 
-		 *
-		 * @param	priority	The priority. Higher value means the camera will be rendered sooner.
+		 * @copydoc	CameraHandler::getProjectionType
 		 */
 		 */
-		void setPriority(INT32 priority) { mPriority = priority; markCoreDirty(); }
+		virtual ProjectionType getProjectionType() const { return mInternal.getProjectionType(); }
 
 
 		/**
 		/**
-		 * @brief	Retrieves layer bitfield that is used when determining which object should the camera render.
+		 * @copydoc	CameraHandler::setOrthoWindow
 		 */
 		 */
-		UINT64 getLayers() const { return mLayers; }
+		virtual void setOrthoWindow(float w, float h) { mInternal.setOrthoWindow(w, h); }
 
 
 		/**
 		/**
-		 * @brief	Sets layer bitfield that is used when determining which object should the camera render.
+		 * @copydoc	CameraHandler::setOrthoWindowHeight
 		 */
 		 */
-		void setLayers(UINT64 layers) { mLayers = layers; markCoreDirty(); }
+		virtual void setOrthoWindowHeight(float h) { mInternal.setOrthoWindowHeight(h); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in world space to screen coordinates (in pixels
-		 *			corresponding to the render target attached to the camera).
+		 * @copydoc	CameraHandler::setOrthoWindowWidth
 		 */
 		 */
-		Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
+		virtual void setOrthoWindowWidth(float w) { mInternal.setOrthoWindowWidth(w); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in world space to normalized clip coordinates 
-		 *			(in [0, 1] range).
+		 * @copydoc	CameraHandler::getOrthoWindowHeight
 		 */
 		 */
-		Vector2 worldToClipPoint(const Vector3& worldPoint) const;
+		virtual float getOrthoWindowHeight() const { return mInternal.getOrthoWindowHeight(); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in world space to point relative to camera's
-		 *			coordinate system (view space).
+		 * @copydoc	CameraHandler::getOrthoWindowWidth
 		 */
 		 */
-		Vector3 worldToViewPoint(const Vector3& worldPoint) const;
+		virtual float getOrthoWindowWidth() const { return mInternal.getOrthoWindowWidth(); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in screen space (pixels corresponding to
-		 *			render target attached to the camera) to a point in world space.
+		 * @copydoc	CameraHandler::setIgnoreSceneRenderables
 		 */
 		 */
-		Vector3 screenToWorldPoint(const Vector2I& screenPoint) const;
+		void setIgnoreSceneRenderables(bool value) { mInternal.setIgnoreSceneRenderables(value); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in screen space (pixels corresponding to
-		 *			render target attached to the camera) to a point relative to
-		 *			camera's coordinate system (view space).
+		 * @copydoc	CameraHandler::getIgnoreSceneRenderables
 		 */
 		 */
-		Vector3 screenToViewPoint(const Vector2I& screenPoint) const;
+		bool getIgnoreSceneRenderables() const { return mInternal.getIgnoreSceneRenderables(); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in screen space (pixels corresponding to
-		 *			render target attached to the camera) to normalized clip 
-		 *			coordinates (in [0, 1] range).
+		 * @copydoc	CameraHandler::getPriority
 		 */
 		 */
-		Vector2 screenToClipPoint(const Vector2I& screenPoint) const;
+		INT32 getPriority() const { return mInternal.getPriority(); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point relative to camera's coordinate system (view space)
-		 *			into a point in world space.
+		 * @copydoc	CameraHandler::setPriority
 		 */
 		 */
-		Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
+		void setPriority(INT32 priority) { mInternal.setPriority(priority); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point relative to camera's coordinate system (view space)
-		 *			into a point in screen space (pixels corresponding to render target 
-		 *			attached to the camera.
+		 * @copydoc	CameraHandler::getLayers
 		 */
 		 */
-		Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
+		UINT64 getLayers() const { return mInternal.getLayers(); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point relative to camera's coordinate system (view space)
-		 *			into normalized clip coordinates (in [0, 1] range).
+		 * @copydoc	CameraHandler::setLayers
 		 */
 		 */
-		Vector2 viewToClipPoint(const Vector3& viewPoint) const;
+		void setLayers(UINT64 layers) { mInternal.setLayers(layers); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
-		 *			a point in world space.
+		 * @copydoc	CameraHandler::worldToScreenPoint
 		 */
 		 */
-		Vector3 clipToWorldPoint(const Vector2& clipPoint) const;
+		Vector2I worldToScreenPoint(const Vector3& worldPoint) const { updateView(); return mInternal.worldToScreenPoint(worldPoint); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
-		 *			a point relative to camera's coordinate system (view space).
+		 * @copydoc	CameraHandler::worldToClipPoint
 		 */
 		 */
-		Vector3 clipToViewPoint(const Vector2& clipPoint) const;
+		Vector2 worldToClipPoint(const Vector3& worldPoint) const { updateView(); return mInternal.worldToClipPoint(worldPoint); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
-		 *			a point in screen space (pixels corresponding to render target attached 
-		 *			to the camera)
+		 * @copydoc	CameraHandler::worldToViewPoint
 		 */
 		 */
-		Vector2I clipToScreenPoint(const Vector2& clipPoint) const;
+		Vector3 worldToViewPoint(const Vector3& worldPoint) const { updateView(); return mInternal.worldToViewPoint(worldPoint); }
 
 
 		/**
 		/**
-		 * @brief	Converts a point in screen space (pixels corresponding to
-		 *			render target attached to the camera) to a ray in world space
-		 *			originating at the selected point on the camera near plane.
+		 * @copydoc	CameraHandler::screenToWorldPoint
 		 */
 		 */
-		Ray screenPointToRay(const Vector2I& screenPoint) const;
+		Vector3 screenToWorldPoint(const Vector2I& screenPoint) const { updateView(); return mInternal.screenToWorldPoint(screenPoint); }
 
 
 		/**
 		/**
-		 * @brief	Projects a point from view to clip space.
+		 * @copydoc	CameraHandler::screenToViewPoint
 		 */
 		 */
-		Vector3 projectPoint(const Vector3& point) const;
+		Vector3 screenToViewPoint(const Vector2I& screenPoint) const { return mInternal.screenToViewPoint(screenPoint); }
 
 
 		/**
 		/**
-		 * @brief	Un-projects a point in clip space to view space.
+		 * @copydoc	CameraHandler::screenToClipPoint
 		 */
 		 */
-		Vector3 unprojectPoint(const Vector3& point) const;
+		Vector2 screenToClipPoint(const Vector2I& screenPoint) const { return mInternal.screenToClipPoint(screenPoint); }
 
 
-        static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
+		/**
+		 * @copydoc	CameraHandler::viewToWorldPoint
+		 */
+		Vector3 viewToWorldPoint(const Vector3& viewPoint) const { updateView(); return mInternal.viewToWorldPoint(viewPoint); }
 
 
-		/************************************************************************/
-		/* 								CORE PROXY                      		*/
-		/************************************************************************/
+		/**
+		 * @copydoc	CameraHandler::viewToScreenPoint
+		 */
+		Vector2I viewToScreenPoint(const Vector3& viewPoint) const { return mInternal.viewToScreenPoint(viewPoint); }
 
 
 		/**
 		/**
-		 * @brief	Checks is the core dirty flag set. This is used by external systems 
-		 *			to know when internal data has changed and core thread potentially needs to be notified.
+		 * @copydoc	CameraHandler::viewToClipPoint
 		 */
 		 */
-		bool _isCoreDirty() const { return mCoreDirtyFlags != 0 || mViewport->_isCoreDirty(); }
+		Vector2 viewToClipPoint(const Vector3& viewPoint) const { return mInternal.viewToClipPoint(viewPoint); }
 
 
 		/**
 		/**
-		 * @brief	Marks the core dirty flag as clean.
+		 * @copydoc	CameraHandler::clipToWorldPoint
 		 */
 		 */
-		void _markCoreClean() { mCoreDirtyFlags = 0; mViewport->_markCoreClean(); }
+		Vector3 clipToWorldPoint(const Vector2& clipPoint) const { updateView(); return mInternal.clipToWorldPoint(clipPoint); }
 
 
 		/**
 		/**
-		 * @brief	Creates a new core proxy from the currently set options. Core proxies ensure
-		 *			that the core thread has all the necessary data, while avoiding the need
-		 *			to manage Camera itself on the core thread.
-		 *
-		 * @note	You generally need to update the core thread with a new proxy whenever core 
-		 *			dirty flag is set.
+		 * @copydoc	CameraHandler::clipToViewPoint
 		 */
 		 */
-		CameraProxyPtr _createProxy() const;
+		Vector3 clipToViewPoint(const Vector2& clipPoint) const { return mInternal.clipToViewPoint(clipPoint); }
 
 
 		/**
 		/**
-		 * @brief	Returns the currently active proxy object, if any.
+		 * @copydoc	CameraHandler::clipToScreenPoint
 		 */
 		 */
-		CameraProxyPtr _getActiveProxy() const { return mActiveProxy; }
+		Vector2I clipToScreenPoint(const Vector2& clipPoint) const { return mInternal.clipToScreenPoint(clipPoint); }
 
 
 		/**
 		/**
-		 * @brief	Changes the currently active proxy object. 
+		 * @copydoc	CameraHandler::screenPointToRay
 		 */
 		 */
-		void _setActiveProxy(const CameraProxyPtr& proxy) { mActiveProxy = proxy; }
+		Ray screenPointToRay(const Vector2I& screenPoint) const { updateView(); return mInternal.screenPointToRay(screenPoint); }
 
 
-	protected:
 		/**
 		/**
-		 * @brief	Calculate projection parameters that are used when constructing the projection matrix.
+		 * @copydoc	CameraHandler::projectPoint
 		 */
 		 */
-		virtual void calcProjectionParameters(float& left, float& right, float& bottom, float& top) const;
+		Vector3 projectPoint(const Vector3& point) const { return mInternal.projectPoint(point); }
 
 
 		/**
 		/**
-		 * @brief	Recalculate frustum if dirty.
+		 * @copydoc	CameraHandler::unprojectPoint
 		 */
 		 */
-		virtual void updateFrustum() const;
+		Vector3 unprojectPoint(const Vector3& point) const { return mInternal.unprojectPoint(point); }
+
+		/************************************************************************/
+		/* 								CORE PROXY                      		*/
+		/************************************************************************/
 
 
 		/**
 		/**
-		 * @brief	Recalculate frustum planes if dirty.
+		 * @copydoc	CameraHandler::_isCoreDirty
 		 */
 		 */
-		virtual void updateFrustumPlanes() const;
+		bool _isCoreDirty() const { return mInternal._isCoreDirty(); }
 
 
 		/**
 		/**
-		 * @brief	Update view matrix from parent position/orientation.
-		 *
-		 * @note	Does nothing when custom view matrix is set.
+		 * @copydoc	CameraHandler::_markCoreClean
 		 */
 		 */
-		virtual void updateView() const;
+		void _markCoreClean() { mInternal._markCoreClean(); }
 
 
 		/**
 		/**
-		 * @brief	Checks if the frustum requires updating.
+		 * @copydoc	CameraHandler::_createProxy
 		 */
 		 */
-		virtual bool isFrustumOutOfDate() const;
+		CameraProxyPtr _createProxy() const { updateView(); return mInternal._createProxy(); }
 
 
 		/**
 		/**
-		 * @brief	Notify camera that the frustum requires to be updated.
+		 * @copydoc	CameraHandler::_getActiveProxy
 		 */
 		 */
-		virtual void invalidateFrustum() const;
+		CameraProxyPtr _getActiveProxy() const { return mInternal._getActiveProxy(); }
 
 
 		/**
 		/**
-		 * @brief	Marks the core data as dirty.
+		 * @copydoc	CameraHandler::_setActiveProxy
 		 */
 		 */
-		void markCoreDirty() { mCoreDirtyFlags = 0xFFFFFFFF; }
+		void _setActiveProxy(const CameraProxyPtr& proxy) { mInternal._setActiveProxy(proxy); }
 
 
     protected:
     protected:
-		ViewportPtr mViewport; /**< Viewport that describes 2D rendering surface. */
-		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
-
-		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. */
-		float mNearDist; /**< Clip any objects close than this. Smaller value decreases depth precision at larger depths. */
-		float mAspect; /**< Width/height viewport ratio. */
-		float mOrthoHeight; /**< Height in world units used for orthographic cameras. */
-		INT32 mPriority; /**< Determines in what order will the camera be rendered. Higher priority means the camera will be rendered sooner. */
-
-		bool mCustomViewMatrix; /**< Is custom view matrix set. */
-		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
-
-		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
-		bool mIgnoreSceneRenderables; /**< Should the camera ignore renderable components. */
-
-		UINT32 mCoreDirtyFlags; /**< True when internal data has changed and core thread wasn't yet informed. */
-		CameraProxyPtr mActiveProxy; /**< Active core proxy if any. */
-
-		mutable Matrix4 mProjMatrixRS; /**< Cached render-system specific projection matrix. */
-		mutable Matrix4 mProjMatrix; /**< Cached projection matrix that determines how are 3D points projected to a 2D viewport. */
-		mutable Matrix4 mViewMatrix; /**< Cached view matrix that determines camera position/orientation. */
-
-		mutable ConvexVolume mFrustum; /**< Main clipping planes describing cameras visible area. */
-		mutable bool mRecalcFrustum; /**< Should frustum be recalculated. */
-		mutable bool mRecalcFrustumPlanes; /**< Should frustum planes be recalculated. */
-		mutable float mLeft, mRight, mTop, mBottom; /**< Frustum extents. */
-		mutable AABox mBoundingBox; /**< Frustum bounding box. */
+		/**
+		 * @brief	Checks if the world transform of the camera changed, and if needed updates
+		 *			the view matrix.
+		 */
+		void updateView() const;
+
+		mutable CameraHandler mInternal;
+		mutable UINT32 mLastUpdateHash;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/* 						COMPONENT OVERRIDES                      		*/

+ 517 - 0
BansheeEngine/Include/BsCameraHandler.h

@@ -0,0 +1,517 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsIReflectable.h"
+#include "BsMatrix4.h"
+#include "BsVector3.h"
+#include "BsVector2.h"
+#include "BsVector2I.h"
+#include "BsAABox.h"
+#include "BsQuaternion.h"
+#include "BsRay.h"
+#include "BsCameraProxy.h"
+#include "BsConvexVolume.h"
+
+namespace BansheeEngine 
+{
+	/**
+	 * @brief	Specified projection type to use by the camera.
+	 */
+    enum ProjectionType
+    {
+        PT_ORTHOGRAPHIC,
+        PT_PERSPECTIVE
+    };
+
+	/**
+	 * @brief	Clip planes that form the camera frustum (visible area).
+	 */
+    enum FrustumPlane
+    {
+        FRUSTUM_PLANE_NEAR = 0,
+        FRUSTUM_PLANE_FAR = 1,
+        FRUSTUM_PLANE_LEFT = 2,
+        FRUSTUM_PLANE_RIGHT = 3,
+        FRUSTUM_PLANE_TOP = 4,
+        FRUSTUM_PLANE_BOTTOM = 5
+    };
+
+	/**
+	 * @brief	Camera determines how is world geometry projected onto a 2D surface. You may
+	 *			position and orient it in space, set options like aspect ratio and field or view
+	 *			and it outputs view and projection matrices required for rendering.
+	 *
+	 * @note	Sim thread only.
+	 */
+    class BS_EXPORT CameraHandler : public IReflectable
+    {
+    public:
+		CameraHandler(RenderTargetPtr target = nullptr,
+			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
+
+		virtual ~CameraHandler();
+
+		/**
+		 * @brief	Returns the viewport used by the camera.
+		 */	
+		ViewportPtr getViewport() const { return mViewport; }
+
+		/**
+		 * @brief	Sets 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.
+		 */
+        virtual void setHorzFOV(const Radian& fovy);
+
+		/**
+		 * @brief	Retrieves the camera horizontal field of view.
+		 */
+        virtual const Radian& getHorzFOV() const;
+
+		/**
+		 * @brief	Sets the distance from the frustum to the near clipping plane. Anything
+		 *			closer than the near clipping plane will not be rendered. Decreasing this value
+		 *			decreases depth buffer precision.
+		 */
+        virtual void setNearClipDistance(float nearDist);
+
+		/**
+		 * @brief	Retrieves the distance from the frustum to the near clipping plane. Anything
+		 *			closer than the near clipping plane will not be rendered. Decreasing this value
+		 *			decreases depth buffer precision.
+		 */
+        virtual float getNearClipDistance() const;
+
+		/**
+		 * @brief	Sets the distance from the frustum to the far clipping plane. Anything
+		 *			farther than the far clipping plane will not be rendered. Increasing this value
+		 *			decreases depth buffer precision.
+		 */
+        virtual void setFarClipDistance(float farDist);
+
+		/**
+		 * @brief	Retrieves the distance from the frustum to the far clipping plane. Anything
+		 *			farther than the far clipping plane will not be rendered. Increasing this value
+		 *			decreases depth buffer precision.
+		 */
+        virtual float getFarClipDistance() const;
+
+		/**
+		 * @brief	Sets the current viewport aspect ratio (width / height).
+		 */
+        virtual void setAspectRatio(float ratio);
+
+		/**
+		 * @brief	Returns current viewport aspect ratio (width / height).
+		 */
+        virtual float getAspectRatio() const;
+
+		/**
+		 * @brief	Sets camera world space position.
+		 */
+		virtual void setPosition(const Vector3& position);
+
+		/**
+		 * @brief	Retrieves camera world space position.
+		 */
+		virtual Vector3 getPosition() const { return mPosition; }
+
+		/**
+		 * @brief	Sets camera world space rotation.
+		 */
+		virtual void setRotation(const Quaternion& rotation);
+
+		/**
+		 * @brief	Retrieves camera world space rotation.
+		 */
+		virtual Quaternion getRotation() const { return mRotation; }
+
+		/** @brief	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.
+		 *
+		 *	@param left		The position where the left clip plane intersect the near clip plane, in view space.
+		 *  @param right	The position where the right clip plane intersect the near clip plane, in view space.
+		 *  @param top		The position where the top clip plane intersect the near clip plane, in view space.
+		 *  @param bottom	The position where the bottom clip plane intersect the near clip plane, in view space.
+		*/
+		virtual void setFrustumExtents(float left, float right, float top, float bottom);
+
+		/** 
+		 * @brief	Resets frustum extents so they are automatically derived from other values.
+		 *			This is only relevant if you have previously set custom extents.
+		 */
+		virtual void resetFrustumExtents(); 
+
+		/** 
+		 * @brief	Returns the extents of the frustum in view space at the near plane.
+		 */
+		virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const;
+
+		/** 
+		 * @brief	Returns the standard projection matrix that determines how are 3D points
+		 *			projected to two dimensions. The layout of this matrix depends on currently
+		 *			used render system.
+		 *
+		 * @note	You should use this matrix when sending the matrix to the render system to remain
+		 *			everything works consistently when other render systems are used.
+		 */
+        virtual const Matrix4& getProjectionMatrixRS() const;
+
+		/** 
+		 * @brief	Returns the standard projection matrix that determines how are 3D points
+		 *			projected to two dimensions. Returned matrix is standard following right-hand
+		 *			rules and depth range of [-1, 1]. 
+		 *
+		 * @note	Different render systems will expect different projection matrix layouts, in which
+		 *			case use getProjectionMatrixRS.
+         */
+        virtual const Matrix4& getProjectionMatrix() const;
+
+		/** 
+		 * @brief	Gets the camera view matrix. Used for positioning/orienting the camera.
+         */
+        virtual const Matrix4& getViewMatrix() const;
+
+		/** 
+		 * @brief	Sets whether the camera should use the custom view matrix.
+		 *			When this is enabled camera will no longer calculate its view matrix
+		 *			based on position/orientation and caller will be resonsible to keep 
+		 *			the view matrix up to date.
+         */
+		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
+
+		/** 
+		 * @brief	Returns true if a custom view matrix is used.
+         */
+		virtual bool isCustomViewMatrixEnabled() const { return mCustomViewMatrix; }
+		
+		/** 
+		 * @brief	Sets whether the camera should use the custom projection matrix.
+		 *			When this is enabled camera will no longer calculate its projection matrix
+		 *			based on field of view, aspect and other parameters and caller will be
+		 *			resonsible to keep the projection matrix up to date.
+         */
+		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
+
+		/** 
+		 * @brief	Returns true if a custom projection matrix is used.
+         */
+		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
+
+		/** 
+		 * @brief	Returns a convex volume representing the visible area of the camera,
+		 *			in local space.
+         */
+        virtual const ConvexVolume& getFrustum() const;
+
+		/** 
+		 * @brief	Returns a convex volume representing the visible area of the camera,
+		 *			in world space.
+         */
+        virtual ConvexVolume getWorldFrustum() const;
+
+		/**
+		 * @brief	Returns the bounding of the frustum.
+		 */
+        const AABox& getBoundingBox() const;
+
+		/**
+		 * @brief	Sets the type of projection used by the camera.
+		 */
+        virtual void setProjectionType(ProjectionType pt);
+
+		/**
+		 * @brief	Returns the type of projection used by the camera.
+		 */
+        virtual ProjectionType getProjectionType() const;
+
+		/**
+		 * @brief	Sets the orthographic window height, for use with orthographic rendering only. 
+		 *
+		 * @param	w	Width of the window in world units.
+		 * @param	h	Height of the window in world units.
+		 *
+		 * @note	Calling this method will recalculate the aspect ratio, use setOrthoWindowHeight or 
+		 *			setOrthoWindowWidth alone if you wish to preserve the aspect ratio but just fit one 
+		 *			or other dimension to a particular size.
+		 */
+		virtual void setOrthoWindow(float w, float h);
+
+		/**
+		 * @brief	Sets the orthographic window height, for use with orthographic rendering only. 
+		 *
+		 * @param	h	Height of the window in world units.
+		 *
+		 * @note	The width of the window will be calculated from the aspect ratio. 
+		 */
+		virtual void setOrthoWindowHeight(float h);
+
+		/**
+		 * @brief	Sets the orthographic window width, for use with orthographic rendering only. 
+		 *
+		 * @param	w	Width of the window in world units.
+		 *
+		 * @note	The height of the window will be calculated from the aspect ratio. 
+		 */
+		virtual void setOrthoWindowWidth(float w);
+
+		/**
+		 * @brief	Gets the orthographic window width in world units, for use with orthographic rendering only. 
+		 */
+		virtual float getOrthoWindowHeight() const;
+
+		/**
+		 * @brief	Gets the orthographic window width in world units, for use with orthographic rendering only. 
+		 *
+		 * @note	This is calculated from the orthographic height and the aspect ratio.
+		 */
+		virtual float getOrthoWindowWidth() const;
+
+		/**
+		 * @brief	This option tells the renderer that this camera should ignore any renderable components.
+		 */
+		void setIgnoreSceneRenderables(bool value) { mIgnoreSceneRenderables = true; markCoreDirty(); }
+
+		/**
+		 * @brief	This option tells the renderer that this camera should ignore any renderable components.
+		 */
+		bool getIgnoreSceneRenderables() const { return mIgnoreSceneRenderables; }
+
+		/**
+		 * @brief	Gets a priority that determines in which orders the cameras are rendered.
+		 *			This only applies to cameras rendering to the same render target. 
+		 */
+		INT32 getPriority() const { return mPriority; }
+
+		/**
+		 * @brief	Sets a priority that determines in which orders the cameras are rendered.
+		 * 			This only applies to cameras rendering to the same render target. 
+		 *
+		 * @param	priority	The priority. Higher value means the camera will be rendered sooner.
+		 */
+		void setPriority(INT32 priority) { mPriority = priority; markCoreDirty(); }
+
+		/**
+		 * @brief	Retrieves layer bitfield that is used when determining which object should the camera render.
+		 */
+		UINT64 getLayers() const { return mLayers; }
+
+		/**
+		 * @brief	Sets layer bitfield that is used when determining which object should the camera render.
+		 */
+		void setLayers(UINT64 layers) { mLayers = layers; markCoreDirty(); }
+
+		/**
+		 * @brief	Converts a point in world space to screen coordinates (in pixels
+		 *			corresponding to the render target attached to the camera).
+		 */
+		Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in world space to normalized clip coordinates 
+		 *			(in [0, 1] range).
+		 */
+		Vector2 worldToClipPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in world space to point relative to camera's
+		 *			coordinate system (view space).
+		 */
+		Vector3 worldToViewPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to a point in world space.
+		 */
+		Vector3 screenToWorldPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to a point relative to
+		 *			camera's coordinate system (view space).
+		 */
+		Vector3 screenToViewPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to normalized clip 
+		 *			coordinates (in [0, 1] range).
+		 */
+		Vector2 screenToClipPoint(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into a point in world space.
+		 */
+		Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into a point in screen space (pixels corresponding to render target 
+		 *			attached to the camera.
+		 */
+		Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point relative to camera's coordinate system (view space)
+		 *			into normalized clip coordinates (in [0, 1] range).
+		 */
+		Vector2 viewToClipPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point in world space.
+		 */
+		Vector3 clipToWorldPoint(const Vector2& clipPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point relative to camera's coordinate system (view space).
+		 */
+		Vector3 clipToViewPoint(const Vector2& clipPoint) const;
+
+		/**
+		 * @brief	Converts a point in normalized clip coordinates ([0, 1] range) to
+		 *			a point in screen space (pixels corresponding to render target attached 
+		 *			to the camera)
+		 */
+		Vector2I clipToScreenPoint(const Vector2& clipPoint) const;
+
+		/**
+		 * @brief	Converts a point in screen space (pixels corresponding to
+		 *			render target attached to the camera) to a ray in world space
+		 *			originating at the selected point on the camera near plane.
+		 */
+		Ray screenPointToRay(const Vector2I& screenPoint) const;
+
+		/**
+		 * @brief	Projects a point from view to clip space.
+		 */
+		Vector3 projectPoint(const Vector3& point) const;
+
+		/**
+		 * @brief	Un-projects a point in clip space to view space.
+		 */
+		Vector3 unprojectPoint(const Vector3& point) const;
+
+        static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
+
+		/************************************************************************/
+		/* 								CORE PROXY                      		*/
+		/************************************************************************/
+
+		/**
+		 * @brief	Checks is the core dirty flag set. This is used by external systems 
+		 *			to know when internal data has changed and core thread potentially needs to be notified.
+		 */
+		bool _isCoreDirty() const { return mCoreDirtyFlags != 0 || mViewport->_isCoreDirty(); }
+
+		/**
+		 * @brief	Marks the core dirty flag as clean.
+		 */
+		void _markCoreClean() { mCoreDirtyFlags = 0; mViewport->_markCoreClean(); }
+
+		/**
+		 * @brief	Creates a new core proxy from the currently set options. Core proxies ensure
+		 *			that the core thread has all the necessary data, while avoiding the need
+		 *			to manage Camera itself on the core thread.
+		 *
+		 * @note	You generally need to update the core thread with a new proxy whenever core 
+		 *			dirty flag is set.
+		 */
+		CameraProxyPtr _createProxy() const;
+
+		/**
+		 * @brief	Returns the currently active proxy object, if any.
+		 */
+		CameraProxyPtr _getActiveProxy() const { return mActiveProxy; }
+
+		/**
+		 * @brief	Changes the currently active proxy object. 
+		 */
+		void _setActiveProxy(const CameraProxyPtr& proxy) { mActiveProxy = proxy; }
+
+	protected:
+		/**
+		 * @brief	Calculate projection parameters that are used when constructing the projection matrix.
+		 */
+		virtual void calcProjectionParameters(float& left, float& right, float& bottom, float& top) const;
+
+		/**
+		 * @brief	Recalculate frustum if dirty.
+		 */
+		virtual void updateFrustum() const;
+
+		/**
+		 * @brief	Recalculate frustum planes if dirty.
+		 */
+		virtual void updateFrustumPlanes() const;
+
+		/**
+		 * @brief	Update view matrix from parent position/orientation.
+		 *
+		 * @note	Does nothing when custom view matrix is set.
+		 */
+		virtual void updateView() const;
+
+		/**
+		 * @brief	Checks if the frustum requires updating.
+		 */
+		virtual bool isFrustumOutOfDate() const;
+
+		/**
+		 * @brief	Notify camera that the frustum requires to be updated.
+		 */
+		virtual void invalidateFrustum() const;
+
+		/**
+		 * @brief	Marks the core data as dirty.
+		 */
+		void markCoreDirty() { mCoreDirtyFlags = 0xFFFFFFFF; }
+
+    protected:
+		ViewportPtr mViewport; /**< Viewport that describes 2D rendering surface. */
+		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
+
+		Vector3 mPosition; /**< World space position. */
+		Quaternion mRotation; /**< World space rotation. */
+
+		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. */
+		float mNearDist; /**< Clip any objects close than this. Smaller value decreases depth precision at larger depths. */
+		float mAspect; /**< Width/height viewport ratio. */
+		float mOrthoHeight; /**< Height in world units used for orthographic cameras. */
+		INT32 mPriority; /**< Determines in what order will the camera be rendered. Higher priority means the camera will be rendered sooner. */
+
+		bool mCustomViewMatrix; /**< Is custom view matrix set. */
+		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
+
+		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
+		bool mIgnoreSceneRenderables; /**< Should the camera ignore renderable components. */
+
+		UINT32 mCoreDirtyFlags; /**< True when internal data has changed and core thread wasn't yet informed. */
+		CameraProxyPtr mActiveProxy; /**< Active core proxy if any. */
+
+		mutable Matrix4 mProjMatrixRS; /**< Cached render-system specific projection matrix. */
+		mutable Matrix4 mProjMatrix; /**< Cached projection matrix that determines how are 3D points projected to a 2D viewport. */
+		mutable Matrix4 mViewMatrix; /**< Cached view matrix that determines camera position/orientation. */
+
+		mutable ConvexVolume mFrustum; /**< Main clipping planes describing cameras visible area. */
+		mutable bool mRecalcFrustum; /**< Should frustum be recalculated. */
+		mutable bool mRecalcFrustumPlanes; /**< Should frustum planes be recalculated. */
+		mutable bool mRecalcView; /**< Should view matrix be recalculated. */
+		mutable float mLeft, mRight, mTop, mBottom; /**< Frustum extents. */
+		mutable AABox mBoundingBox; /**< Frustum bounding box. */
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class CameraHandlerRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+     };
+}

+ 35 - 0
BansheeEngine/Include/BsCameraHandlerRTTI.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsCameraHandler.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT CameraHandlerRTTI : public RTTIType <CameraHandler, IReflectable, CameraHandlerRTTI>
+	{
+	private:
+
+	public:
+		CameraHandlerRTTI()
+		{
+
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "CameraHandler";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_CameraHandler;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return bs_shared_ptr<CameraHandler>();
+		}
+	};
+}

+ 4 - 1
BansheeEngine/Include/BsPrerequisites.h

@@ -80,6 +80,7 @@ namespace BansheeEngine
 	class RenderableHandler;
 	class RenderableHandler;
 	class ProfilerOverlay;
 	class ProfilerOverlay;
 	class DrawHelper;
 	class DrawHelper;
+	class CameraHandler;
 
 
 	// 2D
 	// 2D
 	class TextSprite;
 	class TextSprite;
@@ -99,6 +100,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<Renderable> RenderablePtr;
 	typedef std::shared_ptr<Renderable> RenderablePtr;
 	typedef std::shared_ptr<GUIToggleGroup> GUIToggleGroupPtr;
 	typedef std::shared_ptr<GUIToggleGroup> GUIToggleGroupPtr;
 	typedef std::shared_ptr<RenderableProxy> RenderableProxyPtr;
 	typedef std::shared_ptr<RenderableProxy> RenderableProxyPtr;
+	typedef std::shared_ptr<CameraHandler> CameraHandlerPtr;
 
 
 	typedef GameObjectHandle<GUIWidget> HGUIWidget;
 	typedef GameObjectHandle<GUIWidget> HGUIWidget;
 	typedef GameObjectHandle<Camera> HCamera;
 	typedef GameObjectHandle<Camera> HCamera;
@@ -114,6 +116,7 @@ namespace BansheeEngine
 	{
 	{
 		TID_Camera = 30000,
 		TID_Camera = 30000,
 		TID_Renderable = 30001,
 		TID_Renderable = 30001,
-		TID_SpriteTexture = 30002
+		TID_SpriteTexture = 30002,
+		TID_CameraHandler = 30003,
 	};
 	};
 }
 }

+ 6 - 610
BansheeEngine/Source/BsCamera.cpp

@@ -15,99 +15,16 @@
 
 
 namespace BansheeEngine 
 namespace BansheeEngine 
 {
 {
-	const float Camera::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
-
 	Camera::Camera(const HSceneObject& parent, RenderTargetPtr target, float left, float top, float width, float height)
 	Camera::Camera(const HSceneObject& parent, RenderTargetPtr target, float left, float top, float width, float height)
-        : Component(parent), mProjType(PT_PERSPECTIVE), mHorzFOV(Radian(Math::PI/4.0f)), mFarDist(100000.0f), 
-		mNearDist(100.0f), mAspect(1.33333333333333f), mOrthoHeight(1000), mRecalcFrustum(true), mRecalcFrustumPlanes(true), 
-		mCustomViewMatrix(false), mCustomProjMatrix(false), mFrustumExtentsManuallySet(false), mIgnoreSceneRenderables(false), 
-		mPriority(0), mLayers(0xFFFFFFFFFFFFFFFF), mCoreDirtyFlags(0xFFFFFFFF)
+		: Component(parent), mInternal(target, left, top, width, height), mLastUpdateHash(std::numeric_limits<UINT32>::max())
     {
     {
 		setName("Camera");
 		setName("Camera");
-
-		mViewMatrix = Matrix4::ZERO;
-		mProjMatrixRS = Matrix4::ZERO;
-
-        invalidateFrustum();
-
-		target->synchronize();
-		mViewport = bs_shared_ptr<Viewport, PoolAlloc>(target, left, top, width, height);
     }
     }
 
 
     Camera::~Camera()
     Camera::~Camera()
     {
     {
     }
     }
 
 
-	void Camera::setHorzFOV(const Radian& fov)
-	{
-		mHorzFOV = fov;
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	const Radian& Camera::getHorzFOV() const
-	{
-		return mHorzFOV;
-	}
-
-	void Camera::setFarClipDistance(float farPlane)
-	{
-		mFarDist = farPlane;
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	float Camera::getFarClipDistance() const
-	{
-		return mFarDist;
-	}
-
-	void Camera::setNearClipDistance(float nearPlane)
-	{
-		if (nearPlane <= 0)
-		{
-			BS_EXCEPT(InvalidParametersException, "Near clip distance must be greater than zero.");
-		}
-
-		mNearDist = nearPlane;
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	float Camera::getNearClipDistance() const
-	{
-		return mNearDist;
-	}
-
-	const Matrix4& Camera::getProjectionMatrix() const
-	{
-		updateFrustum();
-
-		return mProjMatrix;
-	}
-
-	const Matrix4& Camera::getProjectionMatrixRS() const
-	{
-		updateFrustum();
-
-		return mProjMatrixRS;
-	}
-
-	const Matrix4& Camera::getViewMatrix() const
-	{
-		updateView();
-
-		return mViewMatrix;
-	}
-
-	const ConvexVolume& Camera::getFrustum() const
-	{
-		// Make any pending updates to the calculated frustum planes
-		updateFrustumPlanes();
-
-		return mFrustum;
-	}
-
 	ConvexVolume Camera::getWorldFrustum() const
 	ConvexVolume Camera::getWorldFrustum() const
 	{
 	{
 		const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
 		const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
@@ -124,539 +41,18 @@ namespace BansheeEngine
 		return ConvexVolume(worldPlanes);
 		return ConvexVolume(worldPlanes);
 	}
 	}
 
 
-	void Camera::calcProjectionParameters(float& left, float& right, float& bottom, float& top) const
-	{ 
-		if (mCustomProjMatrix)
-		{
-			// Convert clipspace corners to camera space
-			Matrix4 invProj = mProjMatrix.inverse();
-			Vector3 topLeft(-0.5f, 0.5f, 0.0f);
-			Vector3 bottomRight(0.5f, -0.5f, 0.0f);
-
-			topLeft = invProj.multiply(topLeft);
-			bottomRight = invProj.multiply(bottomRight);
-
-			left = topLeft.x;
-			top = topLeft.y;
-			right = bottomRight.x;
-			bottom = bottomRight.y;
-		}
-		else
-		{
-			if (mFrustumExtentsManuallySet)
-			{
-				left = mLeft;
-				right = mRight;
-				top = mTop;
-				bottom = mBottom;
-			}
-
-			else if (mProjType == PT_PERSPECTIVE)
-			{
-				Radian thetaY (mHorzFOV * 0.5f);
-				float tanThetaY = Math::tan(thetaY);
-				float tanThetaX = tanThetaY * mAspect;
-
-				float half_w = tanThetaX * mNearDist;
-				float half_h = tanThetaY * mNearDist;
-
-				left = -half_w;
-				right = half_w;
-				bottom = -half_h;
-				top = half_h;
-
-				mLeft = left;
-				mRight = right;
-				mTop = top;
-				mBottom = bottom;
-			}
-			else
-			{
-				float half_w = getOrthoWindowWidth() * 0.5f;
-				float half_h = getOrthoWindowHeight() * 0.5f;
-
-				left = -half_w;
-				right = half_w;
-				bottom = -half_h;
-				top = half_h;
-
-				mLeft = left;
-				mRight = right;
-				mTop = top;
-				mBottom = bottom;
-			}
-		}
-	}
-
-	void Camera::updateFrustum() const
-	{
-		if (isFrustumOutOfDate())
-		{
-			float left, right, bottom, top;
-
-			calcProjectionParameters(left, right, bottom, top);
-
-			if (!mCustomProjMatrix)
-			{
-				float inv_w = 1 / (right - left);
-				float inv_h = 1 / (top - bottom);
-				float inv_d = 1 / (mFarDist - mNearDist);
-
-				if (mProjType == PT_PERSPECTIVE)
-				{
-					float A = 2 * mNearDist * inv_w;
-					float B = 2 * mNearDist * inv_h;
-					float C = (right + left) * inv_w;
-					float D = (top + bottom) * inv_h;
-					float q, qn;
-
-					if (mFarDist == 0)
-					{
-						// Infinite far plane
-						q = Camera::INFINITE_FAR_PLANE_ADJUST - 1;
-						qn = mNearDist * (Camera::INFINITE_FAR_PLANE_ADJUST - 2);
-					}
-					else
-					{
-						q = - (mFarDist + mNearDist) * inv_d;
-						qn = -2 * (mFarDist * mNearDist) * inv_d;
-					}
-
-					mProjMatrix = Matrix4::ZERO;
-					mProjMatrix[0][0] = A;
-					mProjMatrix[0][2] = C;
-					mProjMatrix[1][1] = B;
-					mProjMatrix[1][2] = D;
-					mProjMatrix[2][2] = q;
-					mProjMatrix[2][3] = qn;
-					mProjMatrix[3][2] = -1;
-				} 
-				else if (mProjType == PT_ORTHOGRAPHIC)
-				{
-					float A = 2 * inv_w;
-					float B = 2 * inv_h;
-					float C = - (right + left) * inv_w;
-					float D = - (top + bottom) * inv_h;
-					float q, qn;
-
-					if (mFarDist == 0)
-					{
-						// Can not do infinite far plane here, avoid divided zero only
-						q = - Camera::INFINITE_FAR_PLANE_ADJUST / mNearDist;
-						qn = - Camera::INFINITE_FAR_PLANE_ADJUST - 1;
-					}
-					else
-					{
-						q = - 2 * inv_d;
-						qn = - (mFarDist + mNearDist)  * inv_d;
-					}
-
-					mProjMatrix = Matrix4::ZERO;
-					mProjMatrix[0][0] = A;
-					mProjMatrix[0][3] = C;
-					mProjMatrix[1][1] = B;
-					mProjMatrix[1][3] = D;
-					mProjMatrix[2][2] = q;
-					mProjMatrix[2][3] = qn;
-					mProjMatrix[3][3] = 1;
-				}
-			}
-
-			RenderSystem* renderSystem = BansheeEngine::RenderSystem::instancePtr();
-			renderSystem->convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
-
-			// Calculate bounding box (local)
-			// Box is from 0, down -Z, max dimensions as determined from far plane
-			// If infinite view frustum just pick a far value
-			float farDist = (mFarDist == 0) ? 100000 : mFarDist;
-
-			// Near plane bounds
-			Vector3 min(left, bottom, -farDist);
-			Vector3 max(right, top, 0);
-
-			if (mCustomProjMatrix)
-			{
-				// Some custom projection matrices can have unusual inverted settings
-				// So make sure the AABB is the right way around to start with
-				Vector3 tmp = min;
-				min.floor(max);
-				max.ceil(tmp);
-			}
-
-			if (mProjType == PT_PERSPECTIVE)
-			{
-				// Merge with far plane bounds
-				float radio = farDist / mNearDist;
-				min.floor(Vector3(left * radio, bottom * radio, -farDist));
-				max.ceil(Vector3(right * radio, top * radio, 0));
-			}
-
-			mBoundingBox.setExtents(min, max);
-
-			mRecalcFrustum = false;
-			mRecalcFrustumPlanes = true;
-		}
-	}
-
-	bool Camera::isFrustumOutOfDate() const
-	{
-		return mRecalcFrustum;
-	}
-
 	void Camera::updateView() const
 	void Camera::updateView() const
 	{
 	{
-		if (!mCustomViewMatrix)
+		UINT32 curHash = SO()->getTransformHash();
+		if (curHash != mLastUpdateHash)
 		{
 		{
-			Matrix3 rot;
-			const Quaternion& orientation = sceneObject()->getWorldRotation();
-			const Vector3& position = sceneObject()->getWorldPosition();
+			mInternal.setPosition(SO()->getWorldPosition());
+			mInternal.setRotation(SO()->getWorldRotation());
 
 
-			mViewMatrix.makeView(position, orientation);
+			mLastUpdateHash = curHash;
 		}
 		}
 	}
 	}
 
 
-	void Camera::updateFrustumPlanes() const
-	{
-		updateFrustum();
-
-		if (mRecalcFrustumPlanes)
-		{
-			Vector<Plane> frustumPlanes(6);
-			Matrix4 combo = mProjMatrix;
-
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
-
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
-
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
-			frustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
-
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
-
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
-
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
-			frustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
-
-			for(UINT32 i = 0; i < 6; i++) 
-			{
-				float length = frustumPlanes[i].normal.normalize();
-				frustumPlanes[i].d /= -length;
-			}
-
-			mFrustum = ConvexVolume(frustumPlanes);
-			mRecalcFrustumPlanes = false;
-		}
-	}
-
-	float Camera::getAspectRatio(void) const
-	{
-		return mAspect;
-	}
-
-	void Camera::setAspectRatio(float r)
-	{
-		mAspect = r;
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	const AABox& Camera::getBoundingBox() const
-	{
-		updateFrustum();
-
-		return mBoundingBox;
-	}
-
-	void Camera::setProjectionType(ProjectionType pt)
-	{
-		mProjType = pt;
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	ProjectionType Camera::getProjectionType() const
-	{
-		return mProjType;
-	}
-
-	void Camera::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
-	{
-		mCustomViewMatrix = enable;
-		if (enable)
-		{
-			assert(viewMatrix.isAffine());
-			mViewMatrix = viewMatrix;
-		}
-
-		markCoreDirty();
-	}
-
-	void Camera::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
-	{
-		mCustomProjMatrix = enable;
-
-		if (enable)
-			mProjMatrix = projMatrix;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	void Camera::setOrthoWindow(float w, float h)
-	{
-		mOrthoHeight = h;
-		mAspect = w / h;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	void Camera::setOrthoWindowHeight(float h)
-	{
-		mOrthoHeight = h;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	void Camera::setOrthoWindowWidth(float w)
-	{
-		mOrthoHeight = w / mAspect;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	float Camera::getOrthoWindowHeight() const
-	{
-		return mOrthoHeight;
-	}
-
-	float Camera::getOrthoWindowWidth() const
-	{
-		return mOrthoHeight * mAspect;	
-	}
-
-	void Camera::setFrustumExtents(float left, float right, float top, float bottom)
-	{
-		mFrustumExtentsManuallySet = true;
-		mLeft = left;
-		mRight = right;
-		mTop = top;
-		mBottom = bottom;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	void Camera::resetFrustumExtents()
-	{
-		mFrustumExtentsManuallySet = false;
-
-		invalidateFrustum();
-		markCoreDirty();
-	}
-
-	void Camera::getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
-	{
-		updateFrustum();
-
-		outleft = mLeft;
-		outright = mRight;
-		outtop = mTop;
-		outbottom = mBottom;
-	}
-
-    void Camera::invalidateFrustum() const
-    {
-		mRecalcFrustum = true;
-		mRecalcFrustumPlanes = true;
-    }
-
-	Vector2I Camera::worldToScreenPoint(const Vector3& worldPoint) const
-	{
-		Vector2 clipPoint = worldToClipPoint(worldPoint);
-		return clipToScreenPoint(clipPoint);
-	}
-
-	Vector2 Camera::worldToClipPoint(const Vector3& worldPoint) const
-	{
-		Vector3 viewPoint = worldToViewPoint(worldPoint);
-		return viewToClipPoint(viewPoint);
-	}
-
-	Vector3 Camera::worldToViewPoint(const Vector3& worldPoint) const
-	{
-		return getViewMatrix().multiply3x4(worldPoint);
-	}
-
-	Vector3 Camera::screenToWorldPoint(const Vector2I& screenPoint) const
-	{
-		Vector2 clipPoint = screenToClipPoint(screenPoint);
-		return clipToWorldPoint(clipPoint);
-	}
-
-	Vector3 Camera::screenToViewPoint(const Vector2I& screenPoint) const
-	{
-		Vector2 clipPoint = screenToClipPoint(screenPoint);
-		return clipToViewPoint(clipPoint);
-	}
-
-	Vector2 Camera::screenToClipPoint(const Vector2I& screenPoint) const
-	{
-		Vector2 clipPoint;
-		clipPoint.x = (float)(((screenPoint.x - mViewport->getX()) / (float)mViewport->getWidth()) * 2.0f - 1.0f);
-		clipPoint.y = (float)(((screenPoint.y - mViewport->getY()) / (float)mViewport->getHeight()) * 2.0f - 1.0f);
-
-		return clipPoint;
-	}
-
-	Vector3 Camera::viewToWorldPoint(const Vector3& viewPoint) const
-	{
-		return getViewMatrix().inverseAffine().multiply3x4(viewPoint);
-	}
-
-	Vector2I Camera::viewToScreenPoint(const Vector3& viewPoint) const
-	{
-		Vector2 clipPoint = viewToClipPoint(viewPoint);
-		return clipToScreenPoint(clipPoint);
-	}
-
-	Vector2 Camera::viewToClipPoint(const Vector3& viewPoint) const
-	{
-		Vector3 projPoint = projectPoint(viewPoint);
-
-		return Vector2(projPoint.x, projPoint.y);
-	}
-
-	Vector3 Camera::clipToWorldPoint(const Vector2& clipPoint) const
-	{
-		Vector3 viewPoint = clipToViewPoint(clipPoint);
-		return viewToWorldPoint(viewPoint);
-	}
-
-	Vector3 Camera::clipToViewPoint(const Vector2& clipPoint) const
-	{
-		return unprojectPoint(Vector3(clipPoint.x, clipPoint.y, 0.5f));
-	}
-
-	Vector2I Camera::clipToScreenPoint(const Vector2& clipPoint) const
-	{
-		Vector2I screenPoint;
-		screenPoint.x = Math::roundToInt(mViewport->getX() + (clipPoint.x + 1.0f) * mViewport->getWidth() * 0.5f);
-		screenPoint.y = Math::roundToInt(mViewport->getY() + (clipPoint.y + 1.0f) * mViewport->getHeight() * 0.5f);
-
-		return screenPoint;
-	}
-
-	Ray Camera::screenPointToRay(const Vector2I& screenPoint) const
-	{
-		Vector2 clipPoint = screenToClipPoint(screenPoint);
-		LOGWRN(toString(clipPoint));
-
-		Vector3 near = unprojectPoint(Vector3(clipPoint.x, clipPoint.y, mNearDist));
-		Vector3 far = unprojectPoint(Vector3(clipPoint.x, clipPoint.y, mNearDist + 1.0f));
-
-		Ray ray(near, Vector3::normalize(far - near));
-		ray.transformAffine(mViewMatrix.inverseAffine());
-
-		return ray;
-	}
-
-	Vector3 Camera::projectPoint(const Vector3& point) const
-	{
-		Vector4 projPoint4(point.x, point.y, point.z, 1.0f);
-		projPoint4 = getProjectionMatrixRS().multiply(projPoint4);
-
-		if (Math::abs(projPoint4.w) > 1e-7f)
-		{
-			float invW = 1.0f / projPoint4.w;
-			projPoint4.x *= invW;
-			projPoint4.y *= invW;
-			projPoint4.z *= invW;
-		}
-		else
-		{
-			projPoint4.x = 0.0f;
-			projPoint4.y = 0.0f;
-			projPoint4.z = 0.0f;
-		}
-
-		return Vector3(projPoint4.x, projPoint4.y, projPoint4.z);
-	}
-
-	Vector3 Camera::unprojectPoint(const Vector3& point) const
-	{
-		Vector4 dir4(point.x, point.y, 0.95f, 1.0f); // 0.95f arbitrary
-		dir4 = getProjectionMatrixRS().inverse().multiply(dir4);
-
-		Vector3 dir;
-		dir.x = dir4.x;
-		dir.y = dir4.y;
-		dir.z = dir4.z;
-
-		if (Math::abs(dir4.w) > 1e-7f)
-		{
-			float invW = 1.0f / dir4.w;
-			dir.x *= invW;
-			dir.y *= invW;
-			dir.z *= invW;
-
-			// Find a point along a ray from camera origin to point on near plane we just found, 
-			// at point.z distance from the origin
-
-			float distToPlane = dir.dot(-Vector3::UNIT_Z);
-			if (distToPlane >= 0.0f)
-			{
-				if (mProjType == PT_PERSPECTIVE)
-					dir *= point.z / distToPlane;
-				else
-					dir += Vector3::UNIT_Z * (distToPlane - point.z);
-			}
-		}
-		else
-		{
-			dir.x = 0.0f;
-			dir.y = 0.0f;
-			dir.z = 0.0f;
-		}
-
-		return Vector3(dir.x, dir.y, dir.z);
-	}
-
-	CameraProxyPtr Camera::_createProxy() const
-	{
-		CameraProxyPtr proxy = bs_shared_ptr<CameraProxy>();
-		proxy->layer = mLayers;
-		proxy->priority = mPriority;
-		proxy->projMatrix = getProjectionMatrixRS();
-		proxy->viewMatrix = getViewMatrix();
-		proxy->worldMatrix = SO()->getWorldTfrm();
-		proxy->viewport = mViewport->clone();
-		proxy->frustum = getFrustum();
-		proxy->ignoreSceneRenderables = mIgnoreSceneRenderables;
-		proxy->worldPosition = SO()->getWorldPosition();
-
-		return proxy;
-	}
-
 	RTTITypeBase* Camera::getRTTIStatic()
 	RTTITypeBase* Camera::getRTTIStatic()
 	{
 	{
 		return CameraRTTI::instance();
 		return CameraRTTI::instance();

+ 677 - 0
BansheeEngine/Source/BsCameraHandler.cpp

@@ -0,0 +1,677 @@
+#include "BsCameraHandler.h"
+#include "BsCameraHandlerRTTI.h"
+#include "BsMath.h"
+#include "BsMatrix3.h"
+#include "BsVector2.h"
+#include "BsAABox.h"
+#include "BsSphere.h"
+#include "BsVertexBuffer.h"
+#include "BsIndexBuffer.h"
+#include "BsException.h"
+#include "BsRenderSystem.h"
+#include "BsSceneObject.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	const float CameraHandler::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
+
+	CameraHandler::CameraHandler(RenderTargetPtr target, float left, float top, float width, float height)
+		:mProjType(PT_PERSPECTIVE), mHorzFOV(Radian(Math::PI / 4.0f)), mFarDist(1000.0f),
+		mNearDist(0.05f), mAspect(1.33333333333333f), mOrthoHeight(1000), mRecalcFrustum(true), mRecalcFrustumPlanes(true),
+		mCustomViewMatrix(false), mCustomProjMatrix(false), mFrustumExtentsManuallySet(false), mIgnoreSceneRenderables(false),
+		mPriority(0), mLayers(0xFFFFFFFFFFFFFFFF), mCoreDirtyFlags(0xFFFFFFFF), mRecalcView(true)
+	{
+		mViewMatrix = Matrix4::ZERO;
+		mProjMatrixRS = Matrix4::ZERO;
+
+		invalidateFrustum();
+
+		target->synchronize();
+		mViewport = bs_shared_ptr<Viewport, PoolAlloc>(target, left, top, width, height);
+	}
+
+	CameraHandler::~CameraHandler()
+	{
+	}
+
+	void CameraHandler::setHorzFOV(const Radian& fov)
+	{
+		mHorzFOV = fov;
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	const Radian& CameraHandler::getHorzFOV() const
+	{
+		return mHorzFOV;
+	}
+
+	void CameraHandler::setFarClipDistance(float farPlane)
+	{
+		mFarDist = farPlane;
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	float CameraHandler::getFarClipDistance() const
+	{
+		return mFarDist;
+	}
+
+	void CameraHandler::setNearClipDistance(float nearPlane)
+	{
+		if (nearPlane <= 0)
+		{
+			BS_EXCEPT(InvalidParametersException, "Near clip distance must be greater than zero.");
+		}
+
+		mNearDist = nearPlane;
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	float CameraHandler::getNearClipDistance() const
+	{
+		return mNearDist;
+	}
+
+	const Matrix4& CameraHandler::getProjectionMatrix() const
+	{
+		updateFrustum();
+
+		return mProjMatrix;
+	}
+
+	const Matrix4& CameraHandler::getProjectionMatrixRS() const
+	{
+		updateFrustum();
+
+		return mProjMatrixRS;
+	}
+
+	const Matrix4& CameraHandler::getViewMatrix() const
+	{
+		updateView();
+
+		return mViewMatrix;
+	}
+
+	const ConvexVolume& CameraHandler::getFrustum() const
+	{
+		// Make any pending updates to the calculated frustum planes
+		updateFrustumPlanes();
+
+		return mFrustum;
+	}
+
+	ConvexVolume CameraHandler::getWorldFrustum() const
+	{
+		const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
+		Matrix4 worldMatrix;
+		worldMatrix.setTRS(mPosition, mRotation, Vector3::ONE);
+
+		Vector<Plane> worldPlanes(frustumPlanes.size());
+		UINT32 i = 0;
+		for (auto& plane : frustumPlanes)
+		{
+			worldPlanes[i] = worldMatrix.multiply3x4(plane);
+			i++;
+		}
+
+		return ConvexVolume(worldPlanes);
+	}
+
+	void CameraHandler::calcProjectionParameters(float& left, float& right, float& bottom, float& top) const
+	{
+		if (mCustomProjMatrix)
+		{
+			// Convert clipspace corners to camera space
+			Matrix4 invProj = mProjMatrix.inverse();
+			Vector3 topLeft(-0.5f, 0.5f, 0.0f);
+			Vector3 bottomRight(0.5f, -0.5f, 0.0f);
+
+			topLeft = invProj.multiply(topLeft);
+			bottomRight = invProj.multiply(bottomRight);
+
+			left = topLeft.x;
+			top = topLeft.y;
+			right = bottomRight.x;
+			bottom = bottomRight.y;
+		}
+		else
+		{
+			if (mFrustumExtentsManuallySet)
+			{
+				left = mLeft;
+				right = mRight;
+				top = mTop;
+				bottom = mBottom;
+			}
+
+			else if (mProjType == PT_PERSPECTIVE)
+			{
+				Radian thetaY(mHorzFOV * 0.5f);
+				float tanThetaY = Math::tan(thetaY);
+				float tanThetaX = tanThetaY * mAspect;
+
+				float half_w = tanThetaX * mNearDist;
+				float half_h = tanThetaY * mNearDist;
+
+				left = -half_w;
+				right = half_w;
+				bottom = -half_h;
+				top = half_h;
+
+				mLeft = left;
+				mRight = right;
+				mTop = top;
+				mBottom = bottom;
+			}
+			else
+			{
+				float half_w = getOrthoWindowWidth() * 0.5f;
+				float half_h = getOrthoWindowHeight() * 0.5f;
+
+				left = -half_w;
+				right = half_w;
+				bottom = -half_h;
+				top = half_h;
+
+				mLeft = left;
+				mRight = right;
+				mTop = top;
+				mBottom = bottom;
+			}
+		}
+	}
+
+	void CameraHandler::updateFrustum() const
+	{
+		if (isFrustumOutOfDate())
+		{
+			float left, right, bottom, top;
+
+			calcProjectionParameters(left, right, bottom, top);
+
+			if (!mCustomProjMatrix)
+			{
+				float inv_w = 1 / (right - left);
+				float inv_h = 1 / (top - bottom);
+				float inv_d = 1 / (mFarDist - mNearDist);
+
+				if (mProjType == PT_PERSPECTIVE)
+				{
+					float A = 2 * mNearDist * inv_w;
+					float B = 2 * mNearDist * inv_h;
+					float C = (right + left) * inv_w;
+					float D = (top + bottom) * inv_h;
+					float q, qn;
+
+					if (mFarDist == 0)
+					{
+						// Infinite far plane
+						q = CameraHandler::INFINITE_FAR_PLANE_ADJUST - 1;
+						qn = mNearDist * (CameraHandler::INFINITE_FAR_PLANE_ADJUST - 2);
+					}
+					else
+					{
+						q = -(mFarDist + mNearDist) * inv_d;
+						qn = -2 * (mFarDist * mNearDist) * inv_d;
+					}
+
+					mProjMatrix = Matrix4::ZERO;
+					mProjMatrix[0][0] = A;
+					mProjMatrix[0][2] = C;
+					mProjMatrix[1][1] = B;
+					mProjMatrix[1][2] = D;
+					mProjMatrix[2][2] = q;
+					mProjMatrix[2][3] = qn;
+					mProjMatrix[3][2] = -1;
+				}
+				else if (mProjType == PT_ORTHOGRAPHIC)
+				{
+					float A = 2 * inv_w;
+					float B = 2 * inv_h;
+					float C = -(right + left) * inv_w;
+					float D = -(top + bottom) * inv_h;
+					float q, qn;
+
+					if (mFarDist == 0)
+					{
+						// Can not do infinite far plane here, avoid divided zero only
+						q = -CameraHandler::INFINITE_FAR_PLANE_ADJUST / mNearDist;
+						qn = -CameraHandler::INFINITE_FAR_PLANE_ADJUST - 1;
+					}
+					else
+					{
+						q = -2 * inv_d;
+						qn = -(mFarDist + mNearDist)  * inv_d;
+					}
+
+					mProjMatrix = Matrix4::ZERO;
+					mProjMatrix[0][0] = A;
+					mProjMatrix[0][3] = C;
+					mProjMatrix[1][1] = B;
+					mProjMatrix[1][3] = D;
+					mProjMatrix[2][2] = q;
+					mProjMatrix[2][3] = qn;
+					mProjMatrix[3][3] = 1;
+				}
+			}
+
+			RenderSystem* renderSystem = BansheeEngine::RenderSystem::instancePtr();
+			renderSystem->convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
+
+			// Calculate bounding box (local)
+			// Box is from 0, down -Z, max dimensions as determined from far plane
+			// If infinite view frustum just pick a far value
+			float farDist = (mFarDist == 0) ? 100000 : mFarDist;
+
+			// Near plane bounds
+			Vector3 min(left, bottom, -farDist);
+			Vector3 max(right, top, 0);
+
+			if (mCustomProjMatrix)
+			{
+				// Some custom projection matrices can have unusual inverted settings
+				// So make sure the AABB is the right way around to start with
+				Vector3 tmp = min;
+				min.floor(max);
+				max.ceil(tmp);
+			}
+
+			if (mProjType == PT_PERSPECTIVE)
+			{
+				// Merge with far plane bounds
+				float radio = farDist / mNearDist;
+				min.floor(Vector3(left * radio, bottom * radio, -farDist));
+				max.ceil(Vector3(right * radio, top * radio, 0));
+			}
+
+			mBoundingBox.setExtents(min, max);
+
+			mRecalcFrustum = false;
+			mRecalcFrustumPlanes = true;
+		}
+	}
+
+	bool CameraHandler::isFrustumOutOfDate() const
+	{
+		return mRecalcFrustum;
+	}
+
+	void CameraHandler::updateView() const
+	{
+		if (!mCustomViewMatrix && mRecalcView)
+		{
+			mViewMatrix.makeView(mPosition, mRotation);
+			mRecalcView = false;
+		}
+	}
+
+	void CameraHandler::updateFrustumPlanes() const
+	{
+		updateFrustum();
+
+		if (mRecalcFrustumPlanes)
+		{
+			Vector<Plane> frustumPlanes(6);
+			Matrix4 combo = mProjMatrix;
+
+			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
+			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
+			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
+			frustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
+
+			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
+			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
+			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
+			frustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
+
+			frustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
+			frustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
+			frustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
+			frustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
+
+			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
+			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
+			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
+			frustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
+
+			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
+			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
+			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
+			frustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
+
+			frustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
+			frustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
+			frustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
+			frustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
+
+			for (UINT32 i = 0; i < 6; i++)
+			{
+				float length = frustumPlanes[i].normal.normalize();
+				frustumPlanes[i].d /= -length;
+			}
+
+			mFrustum = ConvexVolume(frustumPlanes);
+			mRecalcFrustumPlanes = false;
+		}
+	}
+
+	float CameraHandler::getAspectRatio(void) const
+	{
+		return mAspect;
+	}
+
+	void CameraHandler::setAspectRatio(float r)
+	{
+		mAspect = r;
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	const AABox& CameraHandler::getBoundingBox() const
+	{
+		updateFrustum();
+
+		return mBoundingBox;
+	}
+
+	void CameraHandler::setProjectionType(ProjectionType pt)
+	{
+		mProjType = pt;
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	ProjectionType CameraHandler::getProjectionType() const
+	{
+		return mProjType;
+	}
+
+	void CameraHandler::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
+	{
+		mCustomViewMatrix = enable;
+		if (enable)
+		{
+			assert(viewMatrix.isAffine());
+			mViewMatrix = viewMatrix;
+		}
+
+		markCoreDirty();
+	}
+
+	void CameraHandler::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
+	{
+		mCustomProjMatrix = enable;
+
+		if (enable)
+			mProjMatrix = projMatrix;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	void CameraHandler::setOrthoWindow(float w, float h)
+	{
+		mOrthoHeight = h;
+		mAspect = w / h;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	void CameraHandler::setOrthoWindowHeight(float h)
+	{
+		mOrthoHeight = h;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	void CameraHandler::setOrthoWindowWidth(float w)
+	{
+		mOrthoHeight = w / mAspect;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	float CameraHandler::getOrthoWindowHeight() const
+	{
+		return mOrthoHeight;
+	}
+
+	float CameraHandler::getOrthoWindowWidth() const
+	{
+		return mOrthoHeight * mAspect;
+	}
+
+	void CameraHandler::setFrustumExtents(float left, float right, float top, float bottom)
+	{
+		mFrustumExtentsManuallySet = true;
+		mLeft = left;
+		mRight = right;
+		mTop = top;
+		mBottom = bottom;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	void CameraHandler::resetFrustumExtents()
+	{
+		mFrustumExtentsManuallySet = false;
+
+		invalidateFrustum();
+		markCoreDirty();
+	}
+
+	void CameraHandler::getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
+	{
+		updateFrustum();
+
+		outleft = mLeft;
+		outright = mRight;
+		outtop = mTop;
+		outbottom = mBottom;
+	}
+
+	void CameraHandler::setPosition(const Vector3& position)
+	{
+		mPosition = position;
+
+		mRecalcView = true;
+	}
+
+	void CameraHandler::setRotation(const Quaternion& rotation)
+	{
+		mRotation = rotation;
+
+		mRecalcView = true;
+	}
+
+	void CameraHandler::invalidateFrustum() const
+	{
+		mRecalcFrustum = true;
+		mRecalcFrustumPlanes = true;
+	}
+
+	Vector2I CameraHandler::worldToScreenPoint(const Vector3& worldPoint) const
+	{
+		Vector2 clipPoint = worldToClipPoint(worldPoint);
+		return clipToScreenPoint(clipPoint);
+	}
+
+	Vector2 CameraHandler::worldToClipPoint(const Vector3& worldPoint) const
+	{
+		Vector3 viewPoint = worldToViewPoint(worldPoint);
+		return viewToClipPoint(viewPoint);
+	}
+
+	Vector3 CameraHandler::worldToViewPoint(const Vector3& worldPoint) const
+	{
+		return getViewMatrix().multiply3x4(worldPoint);
+	}
+
+	Vector3 CameraHandler::screenToWorldPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint = screenToClipPoint(screenPoint);
+		return clipToWorldPoint(clipPoint);
+	}
+
+	Vector3 CameraHandler::screenToViewPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint = screenToClipPoint(screenPoint);
+		return clipToViewPoint(clipPoint);
+	}
+
+	Vector2 CameraHandler::screenToClipPoint(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint;
+		clipPoint.x = (float)(((screenPoint.x - mViewport->getX()) / (float)mViewport->getWidth()) * 2.0f - 1.0f);
+		clipPoint.y = (float)(((screenPoint.y - mViewport->getY()) / (float)mViewport->getHeight()) * 2.0f - 1.0f);
+
+		return clipPoint;
+	}
+
+	Vector3 CameraHandler::viewToWorldPoint(const Vector3& viewPoint) const
+	{
+		return getViewMatrix().inverseAffine().multiply3x4(viewPoint);
+	}
+
+	Vector2I CameraHandler::viewToScreenPoint(const Vector3& viewPoint) const
+	{
+		Vector2 clipPoint = viewToClipPoint(viewPoint);
+		return clipToScreenPoint(clipPoint);
+	}
+
+	Vector2 CameraHandler::viewToClipPoint(const Vector3& viewPoint) const
+	{
+		Vector3 projPoint = projectPoint(viewPoint);
+
+		return Vector2(projPoint.x, projPoint.y);
+	}
+
+	Vector3 CameraHandler::clipToWorldPoint(const Vector2& clipPoint) const
+	{
+		Vector3 viewPoint = clipToViewPoint(clipPoint);
+		return viewToWorldPoint(viewPoint);
+	}
+
+	Vector3 CameraHandler::clipToViewPoint(const Vector2& clipPoint) const
+	{
+		return unprojectPoint(Vector3(clipPoint.x, clipPoint.y, 0.5f));
+	}
+
+	Vector2I CameraHandler::clipToScreenPoint(const Vector2& clipPoint) const
+	{
+		Vector2I screenPoint;
+		screenPoint.x = Math::roundToInt(mViewport->getX() + (clipPoint.x + 1.0f) * mViewport->getWidth() * 0.5f);
+		screenPoint.y = Math::roundToInt(mViewport->getY() + (clipPoint.y + 1.0f) * mViewport->getHeight() * 0.5f);
+
+		return screenPoint;
+	}
+
+	Ray CameraHandler::screenPointToRay(const Vector2I& screenPoint) const
+	{
+		Vector2 clipPoint = screenToClipPoint(screenPoint);
+
+		Vector3 near = unprojectPoint(Vector3(clipPoint.x, clipPoint.y, mNearDist));
+		Vector3 far = unprojectPoint(Vector3(clipPoint.x, clipPoint.y, mNearDist + 1.0f));
+
+		Ray ray(near, Vector3::normalize(far - near));
+		ray.transformAffine(getViewMatrix().inverseAffine());
+
+		return ray;
+	}
+
+	Vector3 CameraHandler::projectPoint(const Vector3& point) const
+	{
+		Vector4 projPoint4(point.x, point.y, point.z, 1.0f);
+		projPoint4 = getProjectionMatrixRS().multiply(projPoint4);
+
+		if (Math::abs(projPoint4.w) > 1e-7f)
+		{
+			float invW = 1.0f / projPoint4.w;
+			projPoint4.x *= invW;
+			projPoint4.y *= invW;
+			projPoint4.z *= invW;
+		}
+		else
+		{
+			projPoint4.x = 0.0f;
+			projPoint4.y = 0.0f;
+			projPoint4.z = 0.0f;
+		}
+
+		return Vector3(projPoint4.x, projPoint4.y, projPoint4.z);
+	}
+
+	Vector3 CameraHandler::unprojectPoint(const Vector3& point) const
+	{
+		Vector4 dir4(point.x, point.y, 0.95f, 1.0f); // 0.95f arbitrary
+		dir4 = getProjectionMatrixRS().inverse().multiply(dir4);
+
+		Vector3 dir;
+		dir.x = dir4.x;
+		dir.y = dir4.y;
+		dir.z = dir4.z;
+
+		if (Math::abs(dir4.w) > 1e-7f)
+		{
+			float invW = 1.0f / dir4.w;
+			dir.x *= invW;
+			dir.y *= invW;
+			dir.z *= invW;
+
+			// Find a point along a ray from camera origin to point on near plane we just found, 
+			// at point.z distance from the origin
+
+			float distToPlane = dir.dot(-Vector3::UNIT_Z);
+			if (distToPlane >= 0.0f)
+			{
+				if (mProjType == PT_PERSPECTIVE)
+					dir *= point.z / distToPlane;
+				else
+					dir += Vector3::UNIT_Z * (distToPlane - point.z);
+			}
+		}
+		else
+		{
+			dir.x = 0.0f;
+			dir.y = 0.0f;
+			dir.z = 0.0f;
+		}
+
+		return Vector3(dir.x, dir.y, dir.z);
+	}
+
+	CameraProxyPtr CameraHandler::_createProxy() const
+	{
+		CameraProxyPtr proxy = bs_shared_ptr<CameraProxy>();
+		proxy->layer = mLayers;
+		proxy->priority = mPriority;
+		proxy->projMatrix = getProjectionMatrixRS();
+		proxy->viewMatrix = getViewMatrix();
+		proxy->worldMatrix.setTRS(mPosition, mRotation, Vector3::ONE);
+		proxy->viewport = mViewport->clone();
+		proxy->frustum = getFrustum();
+		proxy->ignoreSceneRenderables = mIgnoreSceneRenderables;
+		proxy->worldPosition = mPosition;
+
+		return proxy;
+	}
+
+	RTTITypeBase* CameraHandler::getRTTIStatic()
+	{
+		return CameraHandlerRTTI::instance();
+	}
+
+	RTTITypeBase* CameraHandler::getRTTI() const
+	{
+		return CameraHandler::getRTTIStatic();
+	}
+}