Преглед изворни кода

Added root finding code to Math
Added Torus
Added a callback for rendering on core thread and hooked up GizmoManager to it

Marko Pintera пре 11 година
родитељ
комит
547d3f9c59

+ 18 - 0
BansheeCore/Include/BsRenderer.h

@@ -86,7 +86,25 @@ namespace BansheeEngine
 
 
 		/**
 		/**
 		 * @brief	Callback that gets triggered before a viewport gets rendered.
 		 * @brief	Callback that gets triggered before a viewport gets rendered.
+		 *
+		 * @note	Sim thread only
 		 */
 		 */
 		Event<void(const Viewport*, DrawList&)> onRenderViewport;
 		Event<void(const Viewport*, DrawList&)> onRenderViewport;
+
+		/**
+		 * @brief	Callback that gets triggered before main render queue items are rendered
+		 *			to the provided viewport, called from the core thread directly.
+		 *
+		 * @note	Core thread only.
+		 */
+		Event<void(const CameraProxy&)> onCorePreRenderViewport;
+
+		/**
+		 * @brief	Callback that gets triggered after main render queue items are rendered,
+		 *			to the provided viewport, called from the core thread directly.
+		 *
+		 * @note	Core thread only.
+		 */
+		Event<void(const CameraProxy&)> onCorePostRenderViewport;
 	};
 	};
 }
 }

+ 7 - 0
BansheeCore/Include/BsViewport.h

@@ -100,6 +100,13 @@ namespace BansheeEngine
 		 */
 		 */
 		RectI getArea() const;
 		RectI getArea() const;
 
 
+		/**
+		 * @brief	Returns the normalized area of the viewport.
+		 *
+		 * @note	Viewport coordinates are normalized in [0, 1] range.
+		 */
+		RectF getNormArea() const { return mNormArea; }
+
 		/**
 		/**
 		 * @brief	Activates or deactivates clears for color, depth or stencil buffers.
 		 * @brief	Activates or deactivates clears for color, depth or stencil buffers.
 		 *			Buffers will be cleared before rendering to this viewport is performed.
 		 *			Buffers will be cleared before rendering to this viewport is performed.

+ 8 - 1
BansheeEditor/Include/BsGizmoManager.h

@@ -31,7 +31,6 @@ namespace BansheeEngine
 		void drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale);
 		void drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale);
 
 
 		void update();
 		void update();
-		void render();
 		void renderForPicking(std::function<Color(UINT32)> idxToColorCallback);
 		void renderForPicking(std::function<Color(UINT32)> idxToColorCallback);
 		void clearGizmos();
 		void clearGizmos();
 
 
@@ -141,6 +140,7 @@ namespace BansheeEngine
 			const Vector<LineData>& lineData, const Vector<FrustumData>& frustumData, UINT32 numVertices, UINT32 numIndices);
 			const Vector<LineData>& lineData, const Vector<FrustumData>& frustumData, UINT32 numVertices, UINT32 numIndices);
 		TransientMeshPtr buildIconMesh(const Vector<IconData>& iconData, bool pickingOnly, IconRenderDataVecPtr& renderData);
 		TransientMeshPtr buildIconMesh(const Vector<IconData>& iconData, bool pickingOnly, IconRenderDataVecPtr& renderData);
 
 
+		void coreRender(const CameraProxy& camera);
 		void coreRenderSolidGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderSolidGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderWireGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderWireGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderIconGizmos(RectI screenArea, MeshProxyPtr mesh, IconRenderDataVecPtr renderData);
 		void coreRenderIconGizmos(RectI screenArea, MeshProxyPtr mesh, IconRenderDataVecPtr renderData);
@@ -148,6 +148,9 @@ namespace BansheeEngine
 		void coreRenderGizmosForPicking(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderGizmosForPicking(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr mesh);
 		void coreRenderIconGizmosForPicking(RectI screenArea, MeshProxyPtr mesh, IconRenderDataVecPtr renderData);
 		void coreRenderIconGizmosForPicking(RectI screenArea, MeshProxyPtr mesh, IconRenderDataVecPtr renderData);
 
 
+		void coreUpdateData(const MeshProxyPtr& solidMeshProxy, const MeshProxyPtr& wireMeshProxy,
+			const MeshProxyPtr& iconMeshProxy, const IconRenderDataVecPtr& iconRenderData);
+
 		void limitIconSize(UINT32& width, UINT32& height);
 		void limitIconSize(UINT32& width, UINT32& height);
 		void calculateIconColors(const Color& tint, const Camera& camera, UINT32 iconHeight, bool fixedScale,
 		void calculateIconColors(const Color& tint, const Camera& camera, UINT32 iconHeight, bool fixedScale,
 			Color& normalColor, Color& fadedColor);
 			Color& normalColor, Color& fadedColor);
@@ -193,6 +196,10 @@ namespace BansheeEngine
 		TransientMeshPtr mWireMesh;
 		TransientMeshPtr mWireMesh;
 		TransientMeshPtr mIconMesh;
 		TransientMeshPtr mIconMesh;
 
 
+		// Core
+		MeshProxyPtr mSolidMeshProxy;
+		MeshProxyPtr mWireMeshProxy;
+		MeshProxyPtr mIconMeshProxy;
 		IconRenderDataVecPtr mIconRenderData;
 		IconRenderDataVecPtr mIconRenderData;
 
 
 		// Immutable
 		// Immutable

+ 45 - 19
BansheeEditor/Source/BsGizmoManager.cpp

@@ -14,6 +14,9 @@
 #include "BsRenderSystem.h"
 #include "BsRenderSystem.h"
 #include "BsRenderer.h"
 #include "BsRenderer.h"
 #include "BsTransientMesh.h"
 #include "BsTransientMesh.h"
+#include "BsRendererManager.h"
+
+using namespace std::placeholders;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -127,6 +130,9 @@ namespace BansheeEngine
 			fragParams->getParam("alphaCutoff", alphaCutoffParam);
 			fragParams->getParam("alphaCutoff", alphaCutoffParam);
 			alphaCutoffParam.set(PICKING_ALPHA_CUTOFF);
 			alphaCutoffParam.set(PICKING_ALPHA_CUTOFF);
 		}
 		}
+
+		RendererPtr activeRenderer = RendererManager::instance().getActive();
+		activeRenderer->onCorePostRenderViewport.connect(std::bind(&GizmoManager::coreRender, this, _1));
 	}
 	}
 
 
 	void GizmoManager::startGizmo(const HSceneObject& gizmoParent)
 	void GizmoManager::startGizmo(const HSceneObject& gizmoParent)
@@ -279,30 +285,19 @@ namespace BansheeEngine
 		if (mIconMesh != nullptr)
 		if (mIconMesh != nullptr)
 			mIconMeshHeap->dealloc(mIconMesh);
 			mIconMeshHeap->dealloc(mIconMesh);
 
 
+		IconRenderDataVecPtr iconRenderData;
+
 		mSolidMesh = buildSolidMesh(mSolidCubeData, mSolidSphereData, mTotalRequiredSolidVertices, mTotalRequiredSolidIndices);
 		mSolidMesh = buildSolidMesh(mSolidCubeData, mSolidSphereData, mTotalRequiredSolidVertices, mTotalRequiredSolidIndices);
 		mWireMesh = buildWireMesh(mWireCubeData, mWireSphereData, mLineData, mFrustumData, mTotalRequiredWireVertices, mTotalRequiredWireIndices);
 		mWireMesh = buildWireMesh(mWireCubeData, mWireSphereData, mLineData, mFrustumData, mTotalRequiredWireVertices, mTotalRequiredWireIndices);
-		mIconMesh = buildIconMesh(mIconData, false, mIconRenderData);
-
-		clearGizmos();
-	}
+		mIconMesh = buildIconMesh(mIconData, false, iconRenderData);
 
 
-	void GizmoManager::render()
-	{
-		// Note: This must be rendered while Scene view is being rendered
-		Matrix4 viewMat = mCamera->getViewMatrix();
-		Matrix4 projMat = mCamera->getProjectionMatrix();
-		ViewportPtr viewport = mCamera->getViewport();
-
-		gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderSolidGizmos, 
-			this, viewMat, projMat, mSolidMesh->_createProxy(0)));
+		MeshProxyPtr solidMeshProxy = mSolidMesh->_createProxy(0);
+		MeshProxyPtr wireMeshProxy = mWireMesh->_createProxy(0);
+		MeshProxyPtr iconMeshProxy = mIconMesh->_createProxy(0);
 
 
-		gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderWireGizmos, 
-			this, viewMat, projMat, mWireMesh->_createProxy(0)));
+		gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreUpdateData, this, solidMeshProxy, wireMeshProxy, iconMeshProxy, iconRenderData));
 
 
-		RectI screenArea = mCamera->getViewport()->getArea();
-
-		gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderIconGizmos, 
-			this, screenArea, mIconMesh->_createProxy(0), mIconRenderData));
+		clearGizmos();
 	}
 	}
 
 
 	void GizmoManager::renderForPicking(std::function<Color(UINT32)> idxToColorCallback)
 	void GizmoManager::renderForPicking(std::function<Color(UINT32)> idxToColorCallback)
@@ -731,6 +726,37 @@ namespace BansheeEngine
 		fadedColor.a *= 0.2f;
 		fadedColor.a *= 0.2f;
 	}
 	}
 
 
+	void GizmoManager::coreUpdateData(const MeshProxyPtr& solidMeshProxy, const MeshProxyPtr& wireMeshProxy,
+		const MeshProxyPtr& iconMeshProxy, const IconRenderDataVecPtr& iconRenderData)
+	{
+		mSolidMeshProxy = solidMeshProxy;
+		mWireMeshProxy = wireMeshProxy;
+		mIconMeshProxy = iconMeshProxy;
+		mIconRenderData = iconRenderData;
+	}
+
+	void GizmoManager::coreRender(const CameraProxy& camera)
+	{
+		RenderTargetPtr sceneRenderTarget = mCamera->getViewport()->getTarget();
+		if (camera.viewport.getTarget() != sceneRenderTarget)
+			return;
+
+		float width = (float)sceneRenderTarget->getCore()->getProperties().getWidth();
+		float height = (float)sceneRenderTarget->getCore()->getProperties().getHeight();
+
+		RectF normArea = camera.viewport.getNormArea();
+
+		RectI screenArea;
+		screenArea.x = (int)(normArea.x * width);
+		screenArea.y = (int)(normArea.y * height);
+		screenArea.width = (int)(normArea.width * width);
+		screenArea.height = (int)(normArea.height * height);
+
+		coreRenderSolidGizmos(camera.viewMatrix, camera.projMatrix, mSolidMeshProxy);
+		coreRenderWireGizmos(camera.viewMatrix, camera.projMatrix, mWireMeshProxy);
+		coreRenderIconGizmos(screenArea, mIconMeshProxy, mIconRenderData);
+	}
+
 	void GizmoManager::coreRenderSolidGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr meshProxy)
 	void GizmoManager::coreRenderSolidGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr meshProxy)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;

+ 5 - 1
BansheeEditor/Source/BsSceneEditorWidget.cpp

@@ -126,12 +126,16 @@ namespace BansheeEngine
 
 
 	void SceneEditorWidget::determineParentWindow()
 	void SceneEditorWidget::determineParentWindow()
 	{
 	{
+		mParentWindow = nullptr;
+
+		if (mParent == nullptr)
+			return;
+
 		GUIWidget& parentWidget = getParentWidget();
 		GUIWidget& parentWidget = getParentWidget();
 		RenderTargetPtr parentTarget = parentWidget.getTarget()->getTarget();
 		RenderTargetPtr parentTarget = parentWidget.getTarget()->getTarget();
 
 
 		if (!parentTarget->getProperties().isWindow())
 		if (!parentTarget->getProperties().isWindow())
 		{
 		{
-			mParentWindow = nullptr;
 			BS_EXCEPT(InvalidStateException, "Scene view parent render target is not a window. This is not supported.");
 			BS_EXCEPT(InvalidStateException, "Scene view parent render target is not a window. This is not supported.");
 			return;
 			return;
 		}
 		}

+ 2 - 2
BansheeGLRenderSystem/Include/BsGLRenderSystem.h

@@ -567,8 +567,8 @@ namespace BansheeEngine
 		IndexBufferPtr mBoundIndexBuffer;
 		IndexBufferPtr mBoundIndexBuffer;
 		DrawOperationType mCurrentDrawOperation;
 		DrawOperationType mCurrentDrawOperation;
 
 
-		GLContext *mMainContext;
-		GLContext *mCurrentContext;
+		GLContext* mMainContext;
+		GLContext* mCurrentContext;
 
 
 		bool mDrawCallInProgress;
 		bool mDrawCallInProgress;
 
 

+ 4 - 0
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -479,6 +479,8 @@ namespace BansheeEngine
 
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
 
+		onCorePreRenderViewport(cameraProxy);
+
 		if (!cameraProxy.ignoreSceneRenderables)
 		if (!cameraProxy.ignoreSceneRenderables)
 		{
 		{
 			// Update per-object param buffers and queue render elements
 			// Update per-object param buffers and queue render elements
@@ -529,5 +531,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		renderQueue->clear();
 		renderQueue->clear();
+
+		onCorePostRenderViewport(cameraProxy);
 	}
 	}
 }
 }

+ 2 - 0
BansheeUtility/BansheeUtility.vcxproj

@@ -259,6 +259,7 @@
     <ClCompile Include="Source\BsMemorySerializer.cpp" />
     <ClCompile Include="Source\BsMemorySerializer.cpp" />
     <ClCompile Include="Source\BsPath.cpp" />
     <ClCompile Include="Source\BsPath.cpp" />
     <ClCompile Include="Source\BsRectF.cpp" />
     <ClCompile Include="Source\BsRectF.cpp" />
+    <ClCompile Include="Source\BsTorus.cpp" />
     <ClCompile Include="Source\BsVector2I.cpp" />
     <ClCompile Include="Source\BsVector2I.cpp" />
     <ClCompile Include="Source\BsManagedDataBlock.cpp" />
     <ClCompile Include="Source\BsManagedDataBlock.cpp" />
     <ClCompile Include="Source\BsMemoryAllocator.cpp" />
     <ClCompile Include="Source\BsMemoryAllocator.cpp" />
@@ -295,6 +296,7 @@
     <ClInclude Include="Include\BsMemorySerializer.h" />
     <ClInclude Include="Include\BsMemorySerializer.h" />
     <ClInclude Include="Include\BsRectF.h" />
     <ClInclude Include="Include\BsRectF.h" />
     <ClInclude Include="Include\BsHString.h" />
     <ClInclude Include="Include\BsHString.h" />
+    <ClInclude Include="Include\BsTorus.h" />
     <ClInclude Include="Include\BsVector2I.h" />
     <ClInclude Include="Include\BsVector2I.h" />
     <ClInclude Include="Include\BsIReflectable.h" />
     <ClInclude Include="Include\BsIReflectable.h" />
     <ClInclude Include="Include\BsLog.h" />
     <ClInclude Include="Include\BsLog.h" />

+ 6 - 0
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -252,6 +252,9 @@
     <ClInclude Include="Include\BsTestOutput.h">
     <ClInclude Include="Include\BsTestOutput.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsTorus.h">
+      <Filter>Header Files\Math</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsThreadPool.cpp">
     <ClCompile Include="Source\BsThreadPool.cpp">
@@ -401,5 +404,8 @@
     <ClCompile Include="Source\BsTestSuite.cpp">
     <ClCompile Include="Source\BsTestSuite.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsTorus.cpp">
+      <Filter>Source Files\Math</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 244 - 0
BansheeUtility/Include/BsMath.h

@@ -95,6 +95,11 @@ namespace BansheeEngine
          */
          */
         static bool approxEquals(float a, float b, float tolerance = std::numeric_limits<float>::epsilon());
         static bool approxEquals(float a, float b, float tolerance = std::numeric_limits<float>::epsilon());
 
 
+        /**
+         * @brief	Compare 2 doubles, using tolerance for inaccuracies.
+         */
+		static bool approxEquals(double a, double b, double tolerance = std::numeric_limits<double>::epsilon());
+
         /**
         /**
          * @brief	Calculates the tangent space vector for a given set of positions / texture coords.
          * @brief	Calculates the tangent space vector for a given set of positions / texture coords.
          */
          */
@@ -344,6 +349,245 @@ namespace BansheeEngine
 			return clamp01((val - min) / std::max(max - min, 0.0001F));
 			return clamp01((val - min) / std::max(max - min, 0.0001F));
 		}
 		}
 
 
+		/**
+		 * @brief	Solves the linear equation with the parameters A, B.
+		 *			Returns number of roots found and the roots themselves will
+		 *			be output in the "roots" array.
+		 *
+		 * @param	roots	Must be at least size of 1.
+		 *
+		 * @note	Only returns real roots.
+		 */
+		template <typename T>
+		static UINT32 solveLinear(T A, T B, T* roots)
+		{
+			if (!approxEquals(B, (T)0))
+			{
+				roots[0] = -A / B;
+				return 1;
+			}
+			else if (approxEquals(A, (T)0))
+			{
+				roots[0] = 0.0f;
+				return 1;
+			}
+
+			return 0;
+		}
+
+		/**
+		 * @brief	Solves the quadratic equation with the parameters A, B, C.
+		 *			Returns number of roots found and the roots themselves will
+		 *			be output in the "roots" array.
+		 *
+		 * @param	roots	Must be at least size of 2.
+		 *
+		 * @note	Only returns real roots.
+		 */
+		template <typename T>
+		static UINT32 solveQuadratic(T A, T B, T C, T* roots)
+		{
+			if (!approxEquals(C, (T)0))
+			{
+				T discr = B * B - 4 * A * C;
+				if (discr > std::numeric_limits<T>::epsilon())
+				{
+					float temp = ((T)0.5) / C;
+					discr = std::sqrt(discr);
+
+					roots[0] = temp * (-B - discr);
+					roots[1] = temp * (-B + discr);
+
+					return 2;
+				}
+				else if (discr < -std::numeric_limits<T>::epsilon())
+				{
+					return 0;
+				}
+				else
+				{
+					roots[0] = ((T)-0.5) * (B / C);
+					return 1;
+				}
+			}
+			else
+			{
+				return solveLinear(A, B, roots);
+			}
+		}
+
+		/**
+		 * @brief	Solves the cubic equation with the parameters A, B, C, D.
+		 *			Returns number of roots found and the roots themselves will
+		 *			be output in the "roots" array.
+		 *
+		 * @param	roots	Must be at least size of 3.
+		 *
+		 * @note	Only returns real roots.
+		 */
+		template <typename T>
+		static UINT32 solveCubic(T A, T B, T C, T D, T* roots)
+		{
+			static const T THIRD = (1 / (T)3);
+
+			if (!approxEquals(D, (T)0))
+			{
+				T invD = 1 / D;
+				T k0 = A * invD;
+				T k1 = B * invD;
+				T k2 = C * invD;
+
+				T offset = THIRD * k2;
+				T a = k1 - k2 * offset;
+				T b = k0 + k2 * (2 * k2 * k2 - 9 * k1) * (1 / (T)27);
+				T halfB = ((T)0.5) * b;
+
+				T discr = halfB * halfB + a * a * a * (1 / (T)27);
+				if (discr > std::numeric_limits<T>::epsilon())
+				{
+					discr = std::sqrt(discr);
+					T temp = -halfB + discr;
+					if (temp >= (T)0)
+						roots[0] = pow(temp, THIRD);
+					else
+						roots[0] = -pow(-temp, THIRD);
+
+					temp = -halfB - discr;
+					if (temp >= 0)
+						roots[0] += pow(temp, THIRD);
+					else
+						roots[0] -= -pow(-temp, THIRD);
+
+					roots[0] -= offset;
+					return 1;
+				}
+				else if (discr < -std::numeric_limits<T>::epsilon())
+				{
+					T sqrtThree = std::sqrt((T)3);
+					T dist = sqrt(-THIRD * a);
+					T angle = THIRD * atan2(std::sqrt(-discr), -halfB).valueRadians();
+					T angleCos = cos(angle);
+					T angleSin = sin(angle);
+
+					roots[0] = 2 * dist * angleCos - offset;
+					roots[1] = -dist * (angleCos + sqrtThree * angleSin) - offset;
+					roots[2] = -dist * (angleCos - sqrtThree * angleSin) - offset;
+
+					return 3;
+				}
+				else
+				{
+					T temp;
+					if (halfB >= (T)0)
+						temp = -pow(halfB, THIRD);
+					else
+						temp = pow(-halfB, THIRD);
+
+					roots[0] = 2 * temp - offset;
+					roots[1] = -temp - offset;
+					roots[2] = roots[1];
+
+					return 3;
+				}
+			}
+			else
+			{
+				return solveQuadratic(A, B, C, roots);
+			}
+		}
+
+		/**
+		 * @brief	Solves the quartic equation with the parameters A, B, C, D, E.
+		 *			Returns number of roots found and the roots themselves will
+		 *			be output in the "roots" array.
+		 *
+		 * @param	roots	Must be at least size of 4.
+		 *
+		 * @note	Only returns real roots.
+		 */
+		template <typename T>
+		static UINT32 solveQuartic(T A, T B, T C, T D, T E, T* roots)
+		{
+			if (!approxEquals(E, (T)0))
+			{
+				T invE = 1 / E;
+				T k0 = A * invE;
+				T k1 = B * invE;
+				T k2 = C * invE;
+				T k3 = D * invE;
+
+				T r0 = k0 * (4 * k2 - k3 * k3) - k1 * k1;
+				T r1 = k3 * k1 - 4 * k0;
+				T r2 = -k2;
+				solveCubic(r0, r1, r2, (T)1, roots);
+				T y = roots[0];
+
+				UINT32 numRoots = 0;
+				T discr = ((T)0.25) * k3 * k3 - k2 + y;
+				if (discr > std::numeric_limits<T>::epsilon())
+				{
+					T r = sqrt(discr);
+					T t1 = ((T)0.75) * k3 * k3 - r * r - 2*k2;
+					T t2 = (k3 * k2 - 2 * k1 - ((T)0.25) * k3 * k3 * k3) / r;
+
+					T tPlus = t1 + t2;
+					if (tPlus >= ((T)0))
+					{
+						T d = std::sqrt(tPlus);
+						roots[0] = ((T)-0.25) * k3 + ((T)0.5) * (r + d);
+						roots[1] = ((T)-0.25) * k3 + ((T)0.5) * (r - d);
+
+						numRoots += 2;
+					}
+
+					T tMinus = t1 - t2;
+					if (tMinus >= ((T)0))
+					{
+						T e = std::sqrt(tMinus);
+						roots[numRoots++] = ((T)-0.25) * k3 + ((T)0.5) * (e - r);
+						roots[numRoots++] = ((T)-0.25) * k3 - ((T)0.5) * (e + r);
+					}
+				}
+				else if (discr < -std::numeric_limits<T>::epsilon())
+				{
+					numRoots = 0;
+				}
+				else
+				{
+					T t2 = y * y - 4 * k0;
+					if (t2 >= ((T)0))
+					{
+						t2 = 2 * std::sqrt(t2);
+						T t1 = ((T)0.75) * k3 * k3 - 2 * k2;
+
+						T tPlus = t1 + t2;
+						if (tPlus >= ((T)0))
+						{
+							T d = std::sqrt(tPlus);
+							roots[0] = ((T)-0.25) * k3 + ((T)0.5) * d;
+							roots[1] = ((T)-0.25) * k3 + ((T)0.5) * d;
+
+							numRoots += 2;
+						}
+
+						T tMinus = t1 - t2;
+						if (tMinus >= ((T)0))
+						{
+							T e = std::sqrt(tMinus);
+							roots[numRoots++] = ((T)-0.25) * k3 + ((T)0.5) * e;
+							roots[numRoots++] = ((T)-0.25) * k3 - ((T)0.5) * e;
+						}
+					}
+				}
+
+				return numRoots;
+			}
+			else
+			{
+				return solveCubic(A, B, C, D, roots);
+			}
+		}
+
         static const float POS_INFINITY;
         static const float POS_INFINITY;
         static const float NEG_INFINITY;
         static const float NEG_INFINITY;
         static const float PI;
         static const float PI;

+ 26 - 0
BansheeUtility/Include/BsTorus.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsVector3.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Represents a torus at the world center. Outer radius represents
+	 *			the distance from the center, and inner radius represents the radius of the tube.
+	 *			Inner radius must be less or equal than the outer radius.
+	 */
+	class BS_UTILITY_EXPORT Torus
+	{
+	public:
+		Torus(float outerRadius, float innerRadius);
+
+		/**
+		 * @brief	Ray/torus intersection, returns boolean result and distance to nearest intersection point.
+		 */
+		std::pair<bool, float> intersects(const Ray& ray) const;
+
+		float outerRadius;
+		float innerRadius;
+	};
+}

+ 8 - 0
BansheeUtility/Source/BsMath.cpp

@@ -277,6 +277,14 @@ namespace BansheeEngine
             return false;
             return false;
     }
     }
 
 
+	bool Math::approxEquals(double a, double b, double tolerance)
+	{
+		if (fabs(b - a) <= tolerance)
+			return true;
+		else
+			return false;
+	}
+
 	Vector3 Math::calculateTriTangent(const Vector3& position1, const Vector3& position2, 
 	Vector3 Math::calculateTriTangent(const Vector3& position1, const Vector3& position2, 
 		const Vector3& position3, float u1, float v1, float u2, float v2, float u3, float v3)
 		const Vector3& position3, float u1, float v1, float u2, float v2, float u3, float v3)
 	{
 	{

+ 52 - 0
BansheeUtility/Source/BsTorus.cpp

@@ -0,0 +1,52 @@
+#include "BsTorus.h"
+#include "BsRay.h"
+#include "BsMath.h"
+
+namespace BansheeEngine
+{
+	Torus::Torus(float outerRadius, float innerRadius)
+		:outerRadius(outerRadius), innerRadius(innerRadius)
+	{ }
+
+	std::pair<bool, float> Torus::intersects(const Ray& ray) const
+	{
+		const Vector3& org = ray.getOrigin();
+		const Vector3& dir = ray.getDirection();
+
+		float a = org.dot(dir);
+		float b = org.dot(org);
+
+		float outerSqrd = outerRadius*outerRadius;
+		float innerSqrd = innerRadius*innerRadius;
+		float K = a - innerSqrd - outerSqrd;
+
+		float E = 1.0f;
+		float D = 4 * b;
+		float C = 2 * (2 * b*b + K + 2 * outerSqrd*dir.z*dir.z);
+		float B = 4 * (K*b + 2 * outerSqrd*org.z*dir.z);
+		float A = K*K + 4 * outerSqrd*(org.z*org.z - innerSqrd);
+
+		float roots[4];
+		UINT32 numRoots = Math::solveQuartic(A, B, C, D, E, roots);
+
+		if (numRoots > 0)
+		{
+			float nearestT = std::numeric_limits<float>::max();
+
+			for (UINT32 i = 0; i < numRoots; i++)
+			{
+				float t = roots[i];
+				float x = org.x + t*dir.x;
+				float y = org.x + t*dir.y;
+				float l = outerRadius*(Math::PI / 2 - Math::atan2(y, x).valueRadians());
+
+				if (l >= 0 && t < nearestT)
+					nearestT = t;
+			}
+
+			return std::make_pair(true, nearestT);
+		}
+
+		return std::make_pair(false, 0.0f);
+	}
+}

+ 4 - 0
Notes.txt

@@ -69,6 +69,10 @@ Reminders:
   - Will also need GameObject::destroy and GameObject::destroyImmediate. So I can remove GameObjects that might still be referenced that same frame (destroy() would just queue for destruction)
   - Will also need GameObject::destroy and GameObject::destroyImmediate. So I can remove GameObjects that might still be referenced that same frame (destroy() would just queue for destruction)
   - When unloading unused resources I should do it recursively so it unloads any new ones that might have been released during the first unload. 
   - When unloading unused resources I should do it recursively so it unloads any new ones that might have been released during the first unload. 
     (e.g. unloading a sprite texture will probably release its atlas texture as well)
     (e.g. unloading a sprite texture will probably release its atlas texture as well)
+  - Make importer multithreaded. I can add a flag to SpecificImporter that tells me if a certain importer supports multiple threads or not, but even if it doesn't I can run 
+    different importers on different threads this way. And once I hook up progress dialog box, perhaps make it have multiple progress bars in a single window (per thread).
+  - Add FolderManager, extensible C# script that can be attached to a folder (can be in a folder .meta) file. Handles processing of assets in that folder. Can get notified 
+    whenever anything in the folder changes. But is that necessary if I can have asset post- and pre- processor that can filter by folder programatically?
 
 
 
 
 Potential optimizations:
 Potential optimizations:

+ 34 - 13
SceneView.txt

@@ -3,7 +3,6 @@ TODO:
  - Core thread gets stuck on shutdown when OpenGL is used...Somewhere in kernel
  - Core thread gets stuck on shutdown when OpenGL is used...Somewhere in kernel
 
 
 CONCRETE TASK:
 CONCRETE TASK:
- - SceneView editor window: Add a way to detect exact mouse position on the render texture
  - Similar to how I have onRenderViewport callback in Renderer have another one that gets triggered from core thread
  - Similar to how I have onRenderViewport callback in Renderer have another one that gets triggered from core thread
    - Hook up gizmo rendering there
    - Hook up gizmo rendering there
  - Hook up gizmo manager to ScenePicking so gizmos are considered when picking
  - Hook up gizmo manager to ScenePicking so gizmos are considered when picking
@@ -28,19 +27,41 @@ LATER:
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Handles
 Handles
 
 
- - Make a few different base handle types:
-   - Slider 1D (e.g. for movement using an arrow cap)
-   - Slider 2D (e.g. for movement in 2D using a plane render)
-   - Similar for scale/rotation handles  (see Unity for its implementations of those)
+SliderLine - position, direction, length
+  - When initially activated it records position nearest so the line as the starting point
+  - Further mouse dragging also finds nearest position to the line
+  - Difference between those two results in a float value (how much to move along direction from position to reach new position)
+  - Slider line has a capsule + sphere collider size of which can be set manually
+
+SliderPlane - position, normal, size
+  - Similar to line slider only the direction is determined dynamically as well as distance
+  - Outputs a Vector2 (direction * distance moved)
+  - A OOB is used as a collider
+
+SliderDisc - position, normal, radius
+  - When initially activated it records position nearest so the disc as the starting point
+  - Further movement calculates the dynamic direction from the starting point to the current point on the plane the disc lies on
+  - Distance along that direction is returned as amount of movement (similar to line slider)
+  - Outputs a single float
+  - A torus is used as a collider
+
+Handles are always the same size regardless of the distance from camera. (Use same code as from gizmo rendering?)
+These three types can be used for creating MoveHandle, RotationHandle, ScaleHandle
+  - I can potentially move the colliders out of the sliders and add them to the *Handle classes as well
+  - Handle classes will also handle the rendering (using the existing DrawHelper methods)
+
+CONCRETE TASKS:
+ - Need to add capsule, torus and OOB colliders
+    - They need ray intersection code
+ - Line, plane and disc need code for finding nearest point to a ray
+
+Think about C# implementation.
+Take into consideration local vs. global handles
+Free move/rotate/scale handles need to exist as well
+ - Scale is easy, just perform uniform scale. Use SliderPlane oriented towards camera
+ - Move also use SliderPlane oriented towards camera
+ - Rotation use SliderDisc oriented towards camera
 
 
-Handles should have colliders which will be queries whenever user input is detected in scene view
-If any handle is hit the input will not proceed further (e.g. no picking will be done) and that handle control
-will become active.
-
-Base handle types should just be positioned in space and then return value every frame as user moves them.
- - This way they can also easily be used from C# for custom user-made stuff
-
-TODO - Think about this
 See for inspiration: http://docs.unity3d.com/ScriptReference/Handles.html
 See for inspiration: http://docs.unity3d.com/ScriptReference/Handles.html
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------