Browse Source

Tiler work

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
59af4fc97b

+ 1 - 1
include/anki/renderer/DebugDrawer.h

@@ -33,7 +33,7 @@ public:
 	ANKI_USE_RESULT Error create(Renderer* r);
 	ANKI_USE_RESULT Error create(Renderer* r);
 
 
 	void drawGrid();
 	void drawGrid();
-	void drawSphere(F32 radius, I complexity = 4);
+	void drawSphere(F32 radius, I complexity = 8);
 	void drawCube(F32 size = 1.0);
 	void drawCube(F32 size = 1.0);
 	void drawLine(const Vec3& from, const Vec3& to, const Vec4& color);
 	void drawLine(const Vec3& from, const Vec3& to, const Vec4& color);
 
 

+ 14 - 7
include/anki/renderer/Tiler.h

@@ -36,6 +36,18 @@ struct VisibleTiles
 	U32 m_count = 0;
 	U32 m_count = 0;
 	Array<Pair, ANKI_RENDERER_MAX_TILES_X * ANKI_RENDERER_MAX_TILES_Y> 
 	Array<Pair, ANKI_RENDERER_MAX_TILES_X * ANKI_RENDERER_MAX_TILES_Y> 
 		m_tileIds;
 		m_tileIds;
+
+	VisibleTiles() = default;
+
+	void pushBack(U x, U y)
+	{
+		ANKI_ASSERT(x < 0xFF && y < 0xFF);
+
+		Pair p;
+		p.m_x = x;
+		p.m_y = y;
+		m_tileIds[m_count++] = p;
+	}
 };
 };
 
 
 /// Tiler used for visibility tests
 /// Tiler used for visibility tests
@@ -76,8 +88,6 @@ private:
 	Plane* m_nearPlanesW = nullptr;
 	Plane* m_nearPlanesW = nullptr;
 	Plane* m_farPlanesW = nullptr;
 	Plane* m_farPlanesW = nullptr;
 
 
-	DArray<Vec4> m_hullPoints;
-
 	/// A texture of tilesXCount * tilesYCount size and format RG32UI. Used to
 	/// A texture of tilesXCount * tilesYCount size and format RG32UI. Used to
 	/// calculate the near and far planes of the tiles
 	/// calculate the near and far planes of the tiles
 	GlTextureHandle m_rt;
 	GlTextureHandle m_rt;
@@ -99,20 +109,17 @@ private:
 	Timestamp m_planes4UpdateTimestamp = 0;
 	Timestamp m_planes4UpdateTimestamp = 0;
 
 
 	ANKI_USE_RESULT Error initInternal();
 	ANKI_USE_RESULT Error initInternal();
-	ANKI_USE_RESULT Error initHullPoints();
 
 
 	void testRange(const CollisionShape& cs, Bool nearPlane,
 	void testRange(const CollisionShape& cs, Bool nearPlane,
 		U iFrom, U iTo, U jFrom, U jTo, VisibleTiles* visible, 
 		U iFrom, U iTo, U jFrom, U jTo, VisibleTiles* visible, 
 		U& count) const;
 		U& count) const;
 
 
-	Bool testAgainstHull(const CollisionShape& cs, 
-		const U yFrom, const U yTo, const U xFrom, const U xTo) const;
+	void testFastSphere(const Sphere& s, 
+		VisibleTiles* visible, U& count) const;
 
 
 	void update(U32 threadId, PtrSize threadsCount, 
 	void update(U32 threadId, PtrSize threadsCount, 
 		Camera& cam, Bool frustumChanged);
 		Camera& cam, Bool frustumChanged);
 
 
-	void updateHullPoints(U32 threadId, PtrSize threadsCount, Camera& cam);
-
 	/// Calculate and set a top looking plane
 	/// Calculate and set a top looking plane
 	void calcPlaneY(U i, const F32 o6, const F32 near);
 	void calcPlaneY(U i, const F32 o6, const F32 near);
 
 

+ 6 - 0
include/anki/util/Functions.h

@@ -48,6 +48,12 @@ inline T max(T a, T b)
 	return (a > b) ? a : b;
 	return (a > b) ? a : b;
 }
 }
 
 
+template<typename T>
+inline T clamp(T v, T minv, T maxv)
+{
+	return min<T>(max<T>(minv, v), maxv);
+}
+
 /// Check if a number os a power of 2
 /// Check if a number os a power of 2
 template<typename Int>
 template<typename Int>
 inline Bool isPowerOfTwo(Int x)
 inline Bool isPowerOfTwo(Int x)

+ 2 - 2
shaders/IsLp.frag.glsl

@@ -346,9 +346,9 @@ void main()
 #endif
 #endif
 
 
 #if 1
 #if 1
-	if(spotLightsCount != 0)
+	if(pointLightsCount != 0)
 	{
 	{
-		out_color += vec3(0.1);
+		out_color += vec3(0.0, 0.0, 0.9);
 	}
 	}
 #endif
 #endif
 }
 }

+ 3 - 3
src/collision/ConvexHullShape.cpp

@@ -116,11 +116,11 @@ F32 ConvexHullShape::testPlane(const Plane& p) const
 
 
 	if(minDist > 0.0 && maxDist > 0.0)
 	if(minDist > 0.0 && maxDist > 0.0)
 	{
 	{
-		return maxDist;
+		return minDist;
 	}
 	}
-	else if(minDist > 0.0 && maxDist > 0.0)
+	else if(minDist < 0.0 && maxDist < 0.0)
 	{
 	{
-		return minDist;
+		return maxDist;
 	}
 	}
 	else
 	else
 	{
 	{

+ 10 - 2
src/collision/GjkEpa.cpp

@@ -15,7 +15,12 @@ static Vec4 crossAba(const Vec4& a, const Vec4& b)
 {
 {
 	// We need to calculate the (axb)xa but we can use the triple product
 	// We need to calculate the (axb)xa but we can use the triple product
 	// property ax(bxc) = b(a.c) - c(a.b) to make it faster
 	// property ax(bxc) = b(a.c) - c(a.b) to make it faster
-	Vec4 out = b * (a.dot(a)) - a * (a.dot(b));
+	//Vec4 out = b * (a.dot(a)) - a * (a.dot(b));
+	Vec4 out = a.cross(b.cross(a));
+	//printf("+%f %f %f %f\n", out.x(), out.y(), out.z(), out.w());
+	//out = b * (a.dot(a)) - a * (a.dot(b));
+	//printf("-%f %f %f %f\n", out.x(), out.y(), out.z(), out.w());
+
 
 
 	return out;
 	return out;
 }
 }
@@ -215,7 +220,8 @@ Bool Gjk::intersect(const ConvexShape& shape0, const ConvexShape& shape1)
 	m_dir = crossAba(m_simplex[2].m_v - m_simplex[1].m_v, -m_simplex[1].m_v);
 	m_dir = crossAba(m_simplex[2].m_v - m_simplex[1].m_v, -m_simplex[1].m_v);
 	m_count = 2;
 	m_count = 2;
 
 
-	while(1)
+	U iterations = 20;
+	while(iterations--)
 	{
 	{
 		Support a;
 		Support a;
 		support(shape0, shape1, m_dir, a);
 		support(shape0, shape1, m_dir, a);
@@ -230,6 +236,8 @@ Bool Gjk::intersect(const ConvexShape& shape0, const ConvexShape& shape1)
 			return true;
 			return true;
 		}
 		}
 	}
 	}
+
+	return true;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 58 - 39
src/renderer/Dbg.cpp

@@ -13,6 +13,7 @@
 #include "anki/util/Enum.h"
 #include "anki/util/Enum.h"
 #include "anki/misc/ConfigSet.h"
 #include "anki/misc/ConfigSet.h"
 #include "anki/collision/ConvexHullShape.h"
 #include "anki/collision/ConvexHullShape.h"
+#include "anki/util/Rtti.h"
 
 
 namespace anki {
 namespace anki {
 
 
@@ -139,55 +140,73 @@ Error Dbg::run(GlCommandBufferHandle& cmdb)
 
 
 #if 1
 #if 1
 	{
 	{
-		m_drawer->setModelMatrix(Mat4::getIdentity());
-		Sphere s(Vec4(2.0, 1.4, 0.6, 0.0), 6.0);
+		SceneNode& sn = scene.findSceneNode("plight0");
+		SpatialComponent& sp = sn.getComponent<SpatialComponent>();
+		const CollisionShape& cs = sp.getSpatialCollisionShape();
+		const Sphere& sphere = dcast<const Sphere&>(cs);
+		F32 r = sphere.getRadius();
+
+		Mat4 v = cam.getComponent<FrustumComponent>().getViewMatrix();
+		Mat4 p = cam.getComponent<FrustumComponent>().getProjectionMatrix();
+		Mat4 vp = 
+			cam.getComponent<FrustumComponent>().getViewProjectionMatrix();
+
+		Transform t = cam.getComponent<MoveComponent>().getWorldTransform();
+		Mat4 trf(t);
+		Mat3x4 rot = cam.getComponent<MoveComponent>().getWorldTransform().getRotation();
+
 		CollisionDebugDrawer cd(m_drawer);
 		CollisionDebugDrawer cd(m_drawer);
-		cd.visit(s);
-	}
-#endif
 
 
-#if 0
-	{
-		Vec4 storage[] = {
-			Vec4(1.0, 1.0, 1.0, 0.0),
-			Vec4(1.0, 1.0, -1.0, 0.0),
-			Vec4(-1.0, 1.0, -1.0, 0.0),
-			Vec4(-1.0, -1.0, 1.0, 0.0),
-		};
-
-		SceneNode& sn = scene.findSceneNode("horse");
-		MoveComponent& move = sn.getComponent<MoveComponent>();
-
-		ConvexHullShape hull;
-		hull.initStorage(storage, 4);
+		m_drawer->setModelMatrix(Mat4::getIdentity());
+
+		cs.accept(cd);
+
+		m_drawer->setViewProjectionMatrix(Mat4::getIdentity());
+		m_drawer->setModelMatrix(Mat4::getIdentity());
+
+		Vec4 a = vp * sphere.getCenter().xyz1();
+		F32 w = a.w();
+		a /= a.w();
+
 		
 		
-		Sphere s(Vec4(1.0, 0.0, 0.0, 0), 1.0);
+		Vec2 rr;
+		Vec4 n = t.getOrigin() - sphere.getCenter();
+		Vec4 right = rot.getColumn(1).xyz0().cross(n);
+		right.normalize();
 
 
-		Aabb aabb(Vec4(-1.0, -1, -1, 0), Vec4(2, 3, 5, 0));
+		Vec4 b = sphere.getCenter() + right * r;
+		b = vp * b.xyz1();
+		b /= b.w();
+		rr.x() = b.x() - a.x();
 
 
-		Obb obb(Vec4(0.0), Mat3x4::getIdentity(), Vec4(1.0, 2.0, 1.0, 0.0));
+		Vec4 top = n.cross(rot.getColumn(0).xyz0());
+		top.normalize();
 
 
-		CompoundShape comp;
-		comp.addShape(&obb);
-		comp.addShape(&s);
-		comp.addShape(&);
+		b = sphere.getCenter() + top * r;
+		b = vp * b.xyz1();
+		b /= b.w();
+		rr.y() = b.y() - a.y();
 
 
-		comp.transform(move.getWorldTransform());
+#if 0
+		Vec4 a = mvp * sphere.getCenter().xyz1();
+		Vec3 b = a.xyz() / a.w();
 
 
-		if(testCollisionShapes(aabb, comp))
-		{
-			m_drawer->setColor(Vec4(1.0, 0.0, 0.0, 1.0));
-		}
-		else
-		{
-			m_drawer->setColor(Vec4(1.0));
-		}
+		Vec4 aa = mvp * (sphere.getCenter() + rot.getColumn(0).xyz0().getNormalized() * r).xyz1();
+		Vec3 bb = aa.xyz() / aa.w();
+#endif
 
 
-		m_drawer->setModelMatrix(Mat4::getIdentity());
-		CollisionDebugDrawer cd(m_drawer);
+		m_drawer->begin(GL_LINES);
+		m_drawer->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
+
+		m_drawer->pushBackVertex(a.xyz());
+		m_drawer->pushBackVertex(a.xyz() + Vec3(rr.x(), 0, 0));
+
+		m_drawer->pushBackVertex(a.xyz());
+		m_drawer->pushBackVertex(a.xyz() + Vec3(0, rr.y(), 0));
 
 
-		cd.visit(aabb);
-		cd.visit(comp);
+		//m_drawer->pushBackVertex(Vec3(0.0, 0.0, 0.5));
+		//m_drawer->pushBackVertex(Vec3(1.0, 1.0, 0.5));
+		m_drawer->end();
 	}
 	}
 #endif
 #endif
 
 

+ 3 - 3
src/renderer/DebugDrawer.cpp

@@ -470,11 +470,11 @@ void CollisionDebugDrawer::visit(const ConvexHullShape& hull)
 {
 {
 	m_dbg->setModelMatrix(Mat4(hull.getTransform()));
 	m_dbg->setModelMatrix(Mat4(hull.getTransform()));
 	m_dbg->begin(GL_LINES);
 	m_dbg->begin(GL_LINES);
-	const Vec4* points = hull.getPoints();
-	const Vec4* end = points + hull.getPointsCount();
+	const Vec4* points = hull.getPoints() + 1;
+	const Vec4* end = hull.getPoints() + hull.getPointsCount();
 	for(; points != end; ++points)
 	for(; points != end; ++points)
 	{
 	{
-		m_dbg->pushBackVertex(Vec3(0.0));
+		m_dbg->pushBackVertex(hull.getPoints()->xyz());
 		m_dbg->pushBackVertex(points->xyz());
 		m_dbg->pushBackVertex(points->xyz());
 	}
 	}
 	m_dbg->end();
 	m_dbg->end();

+ 251 - 168
src/renderer/Tiler.cpp

@@ -7,6 +7,8 @@
 #include "anki/renderer/Renderer.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/resource/ProgramResource.h"
 #include "anki/resource/ProgramResource.h"
 #include "anki/scene/Camera.h"
 #include "anki/scene/Camera.h"
+#include "anki/scene/SceneGraph.h"
+#include "anki/util/Rtti.h"
 
 
 // Default should be 0
 // Default should be 0
 #define ANKI_TILER_ENABLE_GPU 0
 #define ANKI_TILER_ENABLE_GPU 0
@@ -139,66 +141,9 @@ Error Tiler::initInternal()
 
 
 	cmdBuff.flush();
 	cmdBuff.flush();
 
 
-	// Hull
-	err = initHullPoints();
-
 	return err;
 	return err;
 }
 }
 
 
-//==============================================================================
-ANKI_USE_RESULT Error Tiler::initHullPoints()
-{
-	const U countX = m_r->getTilesCount().x();
-	const U countY = m_r->getTilesCount().y();
-
-	// Grid points + eye
-	const U count = (countX + 1) * (countY + 1) + 1;
-
-	return m_hullPoints.create(getAllocator(), count);
-}
-
-//==============================================================================
-void Tiler::updateHullPoints(U32 threadId, PtrSize threadsCount, Camera& cam)
-{
-	const U countX = m_r->getTilesCount().x() + 1;
-	const U countY = m_r->getTilesCount().y() + 1;
-	const U count = countX * countY;
-	PtrSize start, end;
-	Threadpool::Task::choseStartEnd(threadId, threadsCount, count, start, end);
-
-	const Vec4& projParams = m_r->getProjectionParameters();
-	const Transform& trf = 
-		cam.getComponent<MoveComponent>().getWorldTransform();
-
-	for(U i = start; i < end; ++i)
-	{
-		const U x = i % countX;
-		const U y = i / countX;
-
-		// Calculate the view space position
-		Vec2 clip = Vec2(
-			F32(x) / (countX - 1), 
-			F32(y) / (countY - 1));
-
-		Vec4 view;
-		const F32 depth = 1.0;
-		view.z() = projParams.z() / (projParams.w() + depth);
-		Vec2 viewxy = (clip * 2.0 - 1.0) * projParams.xy() * view.z();
-		view.x() = viewxy.x();
-		view.y() = viewxy.y();
-		view.w() = 0.0;
-
-		// Transform it
-		Vec4 finalPos = trf.transform(view);
-
-		// Store
-		m_hullPoints[i] = finalPos;
-	}
-
-	// The last point is the eye
-	m_hullPoints.getBack() = trf.getOrigin();
-}
-
 //==============================================================================
 //==============================================================================
 void Tiler::runMinMax(GlTextureHandle& depthMap,
 void Tiler::runMinMax(GlTextureHandle& depthMap,
 	GlCommandBufferHandle& cmd)
 	GlCommandBufferHandle& cmd)
@@ -279,10 +224,17 @@ Bool Tiler::test(
 		visible->m_count = 0;
 		visible->m_count = 0;
 	}
 	}
 
 
-	// Call the recursive function
+	// Call the recursive function or the fast path
 	U count = 0;
 	U count = 0;
-	testRange(cs, nearPlane, 0, m_r->getTilesCount().y(), 0,
-		m_r->getTilesCount().x(), visible, count);
+	if(isa<Sphere>(cs))
+	{
+		testFastSphere(dcast<const Sphere&>(cs), visible, count);
+	}
+	else
+	{
+		testRange(cs, nearPlane, 0, m_r->getTilesCount().y(), 0,
+			m_r->getTilesCount().x(), visible, count);
+	}
 
 
 	if(visible)
 	if(visible)
 	{
 	{
@@ -292,25 +244,6 @@ Bool Tiler::test(
 	return count > 0;
 	return count > 0;
 }
 }
 
 
-//==============================================================================
-Bool Tiler::testAgainstHull(const CollisionShape& cs, 
-	const U yFrom, const U yTo, const U xFrom, const U xTo) const
-{
-	Array<Vec4, 5> points;
-	const U countX = m_r->getTilesCount().x() + 1;
-
-	points[0] = m_hullPoints[yFrom * countX + xFrom];
-	points[1] = m_hullPoints[yFrom * countX + xTo];
-	points[2] = m_hullPoints[yTo * countX + xFrom];
-	points[3] = m_hullPoints[yTo * countX + xTo];
-	points[4] = m_hullPoints.getBack();
-
-	ConvexHullShape hull;
-	hull.initStorage(&points[0], points.getSize());
-
-	return testCollisionShapes(hull, cs);
-}
-
 //==============================================================================
 //==============================================================================
 void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 	U yFrom, U yTo, U xFrom, U xTo, VisibleTiles* visible, U& count) const
 	U yFrom, U yTo, U xFrom, U xTo, VisibleTiles* visible, U& count) const
@@ -354,11 +287,7 @@ void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 		{
 		{
 			if(visible)
 			if(visible)
 			{
 			{
-				VisibleTiles::Pair p;
-				ANKI_ASSERT(xFrom < 0xFF && yFrom < 0xFF);
-				p.m_x = static_cast<U8>(xFrom);
-				p.m_y = static_cast<U8>(yFrom);
-				visible->m_tileIds[visible->m_count++] = p;
+				visible->pushBack(xFrom, yFrom);
 			}
 			}
 
 
 			++count;
 			++count;
@@ -367,12 +296,51 @@ void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 		return;
 		return;
 	}
 	}
 
 
+	// Handle the edge case
+	if(ANKI_UNLIKELY(mx == 0 || my == 0))
+	{
+		if(mx == 0)
+		{
+			const Plane& topPlane = m_planesYW[yFrom + my - 1];
+			F32 test = cs.testPlane(topPlane);
+
+			if(test <= 0.0)
+			{
+				testRange(cs, nearPlane, 
+					yFrom, yFrom + my, xFrom, xTo, visible, count);
+			}
+
+			if(test >= 0.0)
+			{
+				testRange(cs, nearPlane, 
+					yFrom + my, yTo, xFrom, xTo, visible, count);
+			}
+		}
+		else
+		{
+			const Plane& rightPlane = m_planesXW[xFrom + mx - 1];
+			F32 test = cs.testPlane(rightPlane);
+
+			if(test <= 0.0)
+			{
+				testRange(cs, nearPlane, 
+					yFrom, yTo, xFrom, xFrom + mx, visible, count);
+			}
+
+			if(test >= 0.0)
+			{
+				testRange(cs, nearPlane, 
+					yFrom, yTo, xFrom + mx, xTo, visible, count);
+			}
+		}
+
+		return;
+	}
+
 	// Do the checks
 	// Do the checks
 	Bool inside[2][2] = {{false, false}, {false, false}};
 	Bool inside[2][2] = {{false, false}, {false, false}};
-	U touchingPlanes = 0;
 
 
 	// Top looking plane check
 	// Top looking plane check
-	if(my > 0)
 	{
 	{
 		// Pick the correct top lookin plane (y)
 		// Pick the correct top lookin plane (y)
 		const Plane& topPlane = m_planesYW[yFrom + my - 1];
 		const Plane& topPlane = m_planesYW[yFrom + my - 1];
@@ -388,8 +356,6 @@ void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 		}
 		}
 		else
 		else
 		{
 		{
-			++touchingPlanes;
-
 			// Possibly all inside
 			// Possibly all inside
 			for(U i = 0; i < 2; i++)
 			for(U i = 0; i < 2; i++)
 			{
 			{
@@ -400,20 +366,8 @@ void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 			}
 			}
 		}
 		}
 	}
 	}
-	else
-	{
-		// Possibly all inside
-		for(U i = 0; i < 2; i++)
-		{
-			for(U j = 0; j < 2; j++)
-			{
-				inside[i][j] = true;
-			}
-		}
-	}
 
 
 	// Right looking plane check
 	// Right looking plane check
-	if(mx > 0)
 	{
 	{
 		// Pick the correct right looking plane (x)
 		// Pick the correct right looking plane (x)
 		const Plane& rightPlane = m_planesXW[xFrom + mx - 1];
 		const Plane& rightPlane = m_planesXW[xFrom + mx - 1];
@@ -430,92 +384,223 @@ void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
 		else
 		else
 		{
 		{
 			// Do nothing and keep the top looking plane check results
 			// Do nothing and keep the top looking plane check results
-			++touchingPlanes;
 		}
 		}
 	}
 	}
 
 
-	// If touching both planes then we need detailed tests
-	//if(touchingPlanes > 2)
+	// Now move lower to the hierarchy
+	if(inside[0][0])
 	{
 	{
-		inside[0][0] = testAgainstHull(cs, 
-			yFrom, yFrom + my, xFrom, xFrom + mx);
-		inside[0][1] = testAgainstHull(cs, 
-			yFrom, yFrom + my, xFrom + mx, xTo);
-		inside[1][0] = testAgainstHull(cs, 
-			yFrom + my, yTo, xFrom, xFrom + mx);
-		inside[1][1] = testAgainstHull(cs, 
-			yFrom + my, yTo, xFrom + mx, xTo);
+		testRange(cs, nearPlane,
+			yFrom, yFrom + my,
+			xFrom, xFrom + mx,
+			visible, count);
 	}
 	}
 
 
-	// Now move lower to the hierarchy
-	if(mx == 0)
+	if(inside[0][1])
 	{
 	{
-		if(inside[0][0])
-		{
-			testRange(cs, nearPlane,
-				yFrom, yFrom + my,
-				xFrom, xTo,
-				visible, count);
-		}
+		testRange(cs, nearPlane,
+			yFrom, yFrom + my,
+			xFrom + mx, xTo,
+			visible, count);
+	}
 
 
-		if(inside[1][0])
-		{
-			testRange(cs, nearPlane,
-				yFrom + my, yTo,
-				xFrom, xTo,
-				visible, count);
-		}
+	if(inside[1][0])
+	{
+		testRange(cs, nearPlane,
+			yFrom + my, yTo,
+			xFrom, xFrom + mx,
+			visible, count);
 	}
 	}
-	else if(my == 0)
+
+	if(inside[1][1])
 	{
 	{
-		if(inside[0][0])
-		{
-			testRange(cs, nearPlane,
-				yFrom, yTo,
-				xFrom, xFrom + mx,
-				visible, count);
-		}
+		testRange(cs, nearPlane,
+			yFrom + my, yTo,
+			xFrom + mx, xTo,
+			visible, count);
+	}
+}
+
+//==============================================================================
+void Tiler::testFastSphere(
+	const Sphere& s, VisibleTiles* visible, U& count) const
+{
+	const Camera& cam = m_r->getSceneGraph().getActiveCamera();
+	const Mat4& vp = 
+		cam.getComponent<FrustumComponent>().getViewProjectionMatrix();
+	const Transform& trf = 
+		cam.getComponent<MoveComponent>().getWorldTransform();
+	const Mat3x4& rot = trf.getRotation();
+
+	const Vec4& scent = s.getCenter();
+	const F32 srad = s.getRadius();
+
+	// Compute projection points
+	Vec4 a, b;
+
+	/*Vec4 a = vp * s.getCenter().xyz1();
+	Vec2 center = a.xy() / a.w();*/
 
 
-		if(inside[0][1])
+	Vec4 eye = trf.getOrigin() - scent;
+
+	if(ANKI_UNLIKELY(eye.getLengthSquared() <= srad * srad))
+	{
+		// Camera totaly inside the sphere
+		for(U y = 0; y < m_r->getTilesCount().y(); ++y)
 		{
 		{
-			testRange(cs, nearPlane,
-				yFrom, yTo,
-				xFrom + mx, xTo,
-				visible, count);
+			for(U x = 0; x < m_r->getTilesCount().x(); ++x)
+			{
+				visible->pushBack(x, y);
+				++count;
+			}
 		}
 		}
+		return;
+	}
+
+	a = rot.getColumn(1).xyz0().cross(eye);
+	a.normalize();
+	b = scent + a * srad;
+	b = vp * b.xyz1();
+	F32 right = b.x() / b.w();
+
+	a = -a;
+	b = scent + a * srad;
+	b = vp * b.xyz1();
+	F32 left = b.x() / b.w();
+
+	a = eye.cross(rot.getColumn(0).xyz0());
+	a.normalize();
+	b = scent + a * srad;
+	b = vp * b.xyz1();
+	F32 top = b.y() / b.w();
+
+	a = -a;
+	b = scent + a * srad;
+	b = vp * b.xyz1();
+	F32 bottom = b.y() / b.w();
+
+	// Do a box test
+	F32 tcountX = m_r->getTilesCount().x();
+	F32 tcountY = m_r->getTilesCount().y();
+
+	I xFrom = floor(tcountX * (left * 0.5 + 0.5));
+	xFrom = clamp<I>(xFrom, 0, m_r->getTilesCount().x());
+	I xTo = ceil(tcountX * (right * 0.5 + 0.5));
+	xTo = min<U>(xTo, m_r->getTilesCount().x());
+	ANKI_ASSERT(xFrom >= 0 && xFrom <= tcountX 
+		&& xTo >= 0 && xTo <= tcountX);
+
+	I yFrom = floor(tcountY * (bottom * 0.5 + 0.5));
+	yFrom = clamp<I>(yFrom, 0, m_r->getTilesCount().y());
+	I yTo = ceil(tcountY * (top * 0.5 + 0.5));
+	yTo = min<I>(yTo, m_r->getTilesCount().y());
+	ANKI_ASSERT(yFrom <= tcountY && yTo <= tcountY);
+	
+#if 0
+	// Since it's possible that the sphere will be ellipsis when projected and
+	// since we don't want to do intersections with eclipses do a trick where
+	// you scale everything and make the eclipse a cyrcle
+	Vec2 scale;
+	F32 maxR;
+
+	if(r.x() > r.y())
+	{
+		scale = Vec2(1.0, r.x() / r.y());
+		maxR = r.x();
 	}
 	}
 	else
 	else
 	{
 	{
-		if(inside[0][0])
-		{
-			testRange(cs, nearPlane,
-				yFrom, yFrom + my,
-				xFrom, xFrom + mx,
-				visible, count);
-		}
+		scale = Vec2(r.y() / r.x(), 1.0);
+		maxR = r.y();
+	}
 
 
-		if(inside[0][1])
-		{
-			testRange(cs, nearPlane,
-				yFrom, yFrom + my,
-				xFrom + mx, xTo,
-				visible, count);
-		}
+	F32 maxR2 = maxR * maxR;
 
 
-		if(inside[1][0])
-		{
-			testRange(cs, nearPlane,
-				yFrom + my, yTo,
-				xFrom, xFrom + mx,
-				visible, count);
-		}
+	Vec2 tileSize(1.0 / tcountX, 1.0 / tcountY);
+	tileSize *= scale;
+
+	c *= scale;
+#endif
 
 
-		if(inside[1][1])
+	Vec2 tileSize(1.0 / tcountX, 1.0 / tcountY);
+
+	a = vp * s.getCenter().xyz1();
+	Vec2 c = a.xy() / a.w();
+	c = c * 0.5 + 0.5;
+
+	for(I y = yFrom; y < yTo; ++y)
+	{
+		for(I x = xFrom; x < xTo; ++x)
 		{
 		{
-			testRange(cs, nearPlane,
-				yFrom + my, yTo,
-				xFrom + mx, xTo,
-				visible, count);
+			// Do detailed tests
+
+			Vec2 tileMin = Vec2(x, y) * tileSize;
+			Vec2 tileMax = Vec2(x + 1, y + 1) * tileSize;
+			
+			// Find closest point of sphere center and tile
+			Vec2 cp(0.0);
+			for(U i = 0; i < 2; ++i)
+			{
+				if(c[i] > tileMax[i])
+				{
+					cp[i] = tileMax[i];
+				}
+				else if (c[i] < tileMin[i])
+				{
+					cp[i] = tileMin[i];
+				}
+				else
+				{
+					// the c lies between min and max
+					cp[i] = c[i];
+				}
+			}
+
+			const Vec4& projParams = m_r->getProjectionParameters();
+			Vec4 view;
+			const F32 depth = 1.0;
+			view.z() = projParams.z() / (projParams.w() + depth);
+			Vec2 viewxy = (cp * 2.0 - 1.0) * projParams.xy() * view.z();
+			view.x() = viewxy.x();
+			view.y() = viewxy.y();
+			view.w() = 0.0;
+
+			Vec3 world = trf.getRotation() * view;
+			LineSegment ls(trf.getOrigin(), world.xyz0());
+			Bool inside = testCollisionShapes(ls, s);
+
+#if 0
+			// Find closest point
+			Vec2 cp(0.0);
+			Vec2 boxMin(x * tileSize.x(), y * tileSize.y());
+			Vec2 boxMax((x + 1) * tileSize.x(), (y + 1) * tileSize.y());
+
+			for(U i = 0; i < 2; ++i)
+			{
+				if(c[i] > boxMax[i])
+				{
+					cp[i] = boxMax[i];
+				}
+				else if (c[i] < boxMin[i])
+				{
+					cp[i] = boxMin[i];
+				}
+				else
+				{
+					// the c lies between min and max
+					cp[i] = c[i];
+				}
+			}
+
+			Vec2 sub = c - cp;
+			Bool inside = sub.getLengthSquared() <= maxR2;
+#endif
+
+			if(inside)
+			{
+				visible->pushBack(x, y);
+				++count;
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -641,8 +726,6 @@ void Tiler::update(U32 threadId, PtrSize threadsCount,
 		++farPlanesW;
 		++farPlanesW;
 	}
 	}
 #endif
 #endif
-
-	updateHullPoints(threadId, threadsCount, cam);
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 11 - 10
testapp/Main.cpp

@@ -73,10 +73,6 @@ Error init()
 	cam->setAll(
 	cam->setAll(
 		renderer.getAspectRatio() * toRad(ang),
 		renderer.getAspectRatio() * toRad(ang),
 		toRad(ang), 0.2, 500.0);
 		toRad(ang), 0.2, 500.0);
-	cam->getComponent<MoveComponent>().
-		setLocalTransform(Transform(Vec4(0.0),
-		Mat3x4(Euler(toRad(0.0), toRad(180.0), toRad(0.0))),
-		1.0));
 	scene.setActiveCamera(cam);
 	scene.setActiveCamera(cam);
 
 
 #if NO_PLAYER
 #if NO_PLAYER
@@ -86,6 +82,11 @@ Error init()
 		1.0));
 		1.0));
 #endif
 #endif
 
 
+	cam->getComponent<MoveComponent>().
+		setLocalTransform(Transform(Vec4(0.0, 0, 10, 0),
+		Mat3x4::getIdentity(),
+		1.0));
+
 	// lights
 	// lights
 #if 0
 #if 0
 	Vec3 lpos(-24.0, 0.1, -10.0);
 	Vec3 lpos(-24.0, 0.1, -10.0);
@@ -231,7 +232,7 @@ Error init()
 	}
 	}
 #endif
 #endif
 
 
-#if 1
+#if 0
 	// horse
 	// horse
 	err = scene.newSceneNode<ModelNode>("horse", horse, 
 	err = scene.newSceneNode<ModelNode>("horse", horse, 
 		"models/horse/horse.ankimdl");
 		"models/horse/horse.ankimdl");
@@ -249,16 +250,16 @@ Error init()
 
 
 	if(1)
 	if(1)
 	{
 	{
-		err = scene.newSceneNode<SpotLight>("plight0", spot);
+		err = scene.newSceneNode<PointLight>("plight0", point);
 		if(err) return err;
 		if(err) return err;
 
 
-		lightc = spot->tryGetComponent<LightComponent>();
-		lightc->setRadius(6.0);
+		lightc = point->tryGetComponent<LightComponent>();
+		lightc->setRadius(10.2);
 		lightc->setDiffuseColor(Vec4(1.0));
 		lightc->setDiffuseColor(Vec4(1.0));
 		lightc->setSpecularColor(Vec4(0.6, 0.6, 0.3, 1.0));
 		lightc->setSpecularColor(Vec4(0.6, 0.6, 0.3, 1.0));
 
 
-		move = spot->tryGetComponent<MoveComponent>();
-		move->setLocalOrigin(Vec4(2.0, 1.4, 0.6, 0.0));
+		move = point->tryGetComponent<MoveComponent>();
+		move->setLocalOrigin(Vec4(1.0, 2.0, 0.2, 0.0));
 	}
 	}
 
 
 #if 0
 #if 0