Browse Source

Collision detection

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
aa931d5b03

+ 5 - 3
include/anki/collision/CollisionShape.h

@@ -22,14 +22,16 @@ class CollisionShape
 {
 public:
 	/// Collision shape type
+	/// @note WARNING: Order is important
 	enum class Type: U8
 	{
-		LINE_SEG,
 		PLANE,
-		SPHERE,
+		COMPOUND,
 		AABB,
+		SPHERE,
+		LINE_SEG,
 		OBB,
-		COMPOUND
+		COUNT
 	};
 
 	/// Generic mutable visitor

+ 6 - 4
include/anki/collision/GjkEpa.h

@@ -48,24 +48,26 @@ private:
 class GjkEpa
 {
 public:
-	detail::Polytope* m_poly; // XXX
+	//detail::Polytope* m_poly; // XXX
 
-	GjkEpa(U32 maxSimplexSize, U32 maxFaceCount)
+	GjkEpa(U32 maxSimplexSize, U32 maxFaceCount, U32 maxIterations)
 	:	m_maxSimplexSize(maxSimplexSize),
-		m_maxFaceCount(maxFaceCount)
+		m_maxFaceCount(maxFaceCount),
+		m_maxIterations(maxIterations)
 	{}
 
 	~GjkEpa()
 	{}
 
 	Bool intersect(const ConvexShape& shape0, const ConvexShape& shape1,
-		ContactPoint& contact, StackAllocator<U8>& alloc);
+		ContactPoint& contact, CollisionTempAllocator<U8>& alloc);
 
 private:
 	using Support = detail::Support;
 
 	U32 m_maxSimplexSize;
 	U32 m_maxFaceCount;
+	U32 m_maxIterations;
 };
 
 /// @}

+ 12 - 6
include/anki/collision/GjkEpaInternal.h

@@ -7,8 +7,7 @@
 #define ANKI_COLLISION_GJK_EPA_INTERNAL_H
 
 #include "anki/Math.h"
-#include "anki/util/Allocator.h"
-#include "anki/util/Vector.h"
+#include "anki/collision/Common.h"
 
 namespace anki {
 namespace detail {
@@ -134,6 +133,11 @@ public:
 		m_dead = true;
 	}
 
+	void revive()
+	{
+		m_dead = false;
+	}
+
 private:
 	mutable Array<U32, 3> m_idx;
 	mutable Vec4 m_normal;
@@ -148,7 +152,9 @@ class Polytope
 	friend class Face;
 
 public:
-	Polytope(StackAllocator<U8>& alloc, U32 maxSimplexSize, U32 maxFaceCount)
+	Polytope(CollisionTempAllocator<U8>& alloc, 
+		U32 maxSimplexSize, 
+		U32 maxFaceCount)
 	:	m_maxSimplexSize(maxSimplexSize),
 		m_maxFaceCount(maxFaceCount),
 		m_simplex(alloc),
@@ -180,10 +186,10 @@ public: // XXX
 	U32 m_maxSimplexSize;
 	U32 m_maxFaceCount;
 
-	Vector<Support, StackAllocator<Support>> m_simplex;
-	Vector<Face, StackAllocator<Face>> m_faces;
+	Vector<Support, CollisionTempAllocator<Support>> m_simplex;
+	Vector<Face, CollisionTempAllocator<Face>> m_faces;
 
-	StackAllocator<U8> getAllocator() const
+	CollisionTempAllocator<U8> getAllocator() const
 	{
 		return m_simplex.get_allocator();
 	}

+ 27 - 12
include/anki/collision/Tests.h

@@ -9,7 +9,6 @@
 #include "anki/collision/Common.h"
 
 namespace anki {
-namespace detail {
 
 /// @addtogroup collision
 /// @{
@@ -18,27 +17,43 @@ namespace detail {
 /// shapes
 /// @code
 /// +------+------+------+------+------+------+------+
-/// |      | LS   | OBB  | P    | S    | AABB |      |
+/// |      | PL   | COMP | AABB | SPH  | LINE | OBB  |
 /// +------+------+------+------+------+------+------+
-/// | LS   | N/A  | OK   | OK   | OK   | OK   |      |
+/// | PL   | N/A  | OK   | OK   | OK   | OK   | OK   |
 /// +------+------+------+------+------+------+------+
-/// | OBB  |      | OK   | OK   | OK   | OK   |      |
+/// | COMP |      | OK   | OK   | OK   | OK   | OK   |
 /// +------+------+------+------+------+------+------+
-/// | P    |      |      | OK   | OK   | OK   |      |
+/// | AABB |      |      | OK   | OK   | OK   | OK   |
 /// +------+------+------+------+------+------+------+
-/// | S    |      |      |      | OK   | OK   |      |
+/// | SPH  |      |      |      | OK   | OK   | OK   |
 /// +------+------+------+------+------+------+------+
-/// | AABB |      |      |      |      | OK   |      |
+/// | LINE |      |      |      |      | OK   | OK   |
+/// +------+------+------+------+------+------+------+
+/// | OBB  |      |      |      |      |      | OK   |
 /// +------+------+------+------+------+------+------+
 /// @endcode
-
-
-// 2nd line
-U test(const Obb& a, const Obb& b, CollisionTempVector<ContactPoint>& points);
+class CollisionTester
+{
+public:
+	using TestCallback = U (*)(CollisionTester& self,
+		const CollisionShape&, const CollisionShape&, 
+		CollisionTempVector<ContactPoint>& points);
+
+	CollisionTempAllocator<U8>& _getAllocator()
+	{
+		return m_alloc;
+	}
+
+	// Generic test function
+	U test(const CollisionShape& a, const CollisionShape& b, 
+		CollisionTempVector<ContactPoint>& points);
+
+private:
+	CollisionTempAllocator<U8> m_alloc;
+};
 
 /// @}
 
-} // end namespace detail 
 } // end namespace anki
 
 #endif

+ 8 - 3
include/anki/renderer/DebugDrawer.h

@@ -43,7 +43,7 @@ public:
 
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
 	/// @{
-	void begin(); ///< Initiates the draw
+	void begin(GLenum primitive); ///< Initiates the draw
 	void end(); ///< Draws
 	void pushBackVertex(const Vec3& pos); ///< Something like glVertex
 	/// Something like glColor
@@ -80,10 +80,13 @@ private:
 	Mat4 m_mMat;
 	Mat4 m_vpMat;
 	Mat4 m_mvpMat; ///< Optimization
-	U32 m_vertexPointer;
+	U32 m_lineVertCount;
+	U32 m_triVertCount;
 	Vec3 m_crntCol;
+	GLenum m_primitive;
 
-	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientVerts;
+	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientLineVerts;
+	Array<Vertex, MAX_POINTS_PER_DRAW> m_clientTriVerts;
 
 	GlBufferHandle m_vertBuff;
 
@@ -91,6 +94,8 @@ private:
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// pairs)
 	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
+
+	void flushInternal(GLenum primitive);
 };
 
 /// Contains methods to render the collision shapes

+ 12 - 4
include/anki/util/File.h

@@ -103,10 +103,15 @@ public:
 	void read(void* buff, PtrSize size);
 
 	/// Read all the contents of a text file
-	void readAllText(String& out);
-
-	/// Read all the contents of a text file and return the result in lines
-	void readAllTextLines(StringList& lines);
+	/// If the file is not rewined it will probably fail
+	template<typename TContainer>
+	void readAllText(TContainer& out)
+	{
+		PtrSize size = getSize();
+		out.resize(size + 1);
+		read(&out[0], size);
+		out[size] = '\0';
+	}
 
 	/// Read 32bit unsigned integer. Set the endianness if the file's 
 	/// endianness is different from the machine's
@@ -180,6 +185,9 @@ private:
 	/// Open an Android file
 	void openAndroidFile(const char* filename, OpenFlag flags);
 #endif
+
+	/// The file should be open
+	PtrSize getSize();
 };
 
 /// Return true if directory exists?

+ 13 - 0
include/anki/util/Memory.h

@@ -104,6 +104,9 @@ class StackMemoryPool
 	friend class ChainMemoryPool;
 
 public:
+	/// The type of the pool's snapshot
+	using Snapshot = void*;
+
 	/// Default constructor
 	StackMemoryPool()
 		: m_impl(nullptr)
@@ -161,6 +164,16 @@ public:
 	/// Get the number of users for this pool
 	U32 getUsersCount() const;
 
+	/// Get a snapshot of the current state that can be used to reset the 
+	/// pool's state later on. Not recommended on multithreading scenarios
+	/// @return The current state of the pool
+	Snapshot getShapshot() const;
+
+	/// Reset the poll using a snapshot. Not recommended on multithreading 
+	/// scenarios
+	/// @param s The snapshot to be used
+	void resetUsingSnapshot(Snapshot s);
+
 private:
 	// Forward. Hide the implementation because Memory.h is the base of other
 	// files and should not include them

+ 0 - 1
include/anki/util/String.h

@@ -19,7 +19,6 @@ using BasicString = std::basic_string<TChar, std::char_traits<TChar>, TAlloc>;
 
 using String = BasicString<char, std::allocator<char>>;
 
-
 /// Trim a string
 /// Remove the @p what from the front and back of @p str
 template<typename TString>

+ 10 - 5
src/collision/GjkEpa.cpp

@@ -242,7 +242,7 @@ Bool Gjk::intersect(const ConvexShape& shape0, const ConvexShape& shape1)
 
 //==============================================================================
 Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
-	ContactPoint& contact, StackAllocator<U8>& alloc)
+	ContactPoint& contact, CollisionTempAllocator<U8>& alloc)
 {
 	// Do the intersection test
 	Gjk gjk;
@@ -254,11 +254,9 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 	// Init polytope
 	detail::Polytope* poly = alloc.newInstance<detail::Polytope>(
 		alloc, m_maxSimplexSize, m_maxFaceCount);
-	m_poly = poly;
+	//m_poly = poly;
 	poly->init(gjk.m_simplex);
 
-	std::cout << "-----------------------" << std::endl;
-
 	U iterations = 0;
 	while(1) 
 	{
@@ -278,8 +276,13 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 			//|| m_faceCount == m_faces.size() - 2
 			//|| m_count == m_simplexArr.size() - 1
 			//|| pIdx != m_count
-			|| iterations == 5)
+			|| iterations == 10)
 		{
+			if(iterations == 10)
+			{
+				std::cout << "too many iterations" << std::endl;
+			}
+
 			/*if(pIdx != m_count)
 			{
 				contact.m_normal = m_faces[prevFaceIndex].m_normal;
@@ -305,6 +308,8 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 		++iterations;
 	}
 
+	alloc.deleteInstance(poly);
+
 	return true;
 }
 

+ 40 - 19
src/collision/GjkEpaInternal.cpp

@@ -20,6 +20,14 @@ static inline std::ostream& operator<<(std::ostream& os, const Edge& e)
 // Face                                                                        =
 //==============================================================================
 
+//==============================================================================
+static inline std::ostream& operator<<(std::ostream& os, const Face& f) 
+{
+	auto idx = f.idx();
+	os << idx[0] << " " << idx[1] << " " << idx[2];
+	return os;
+}
+
 //==============================================================================
 const Vec4& Face::normal(Polytope& poly, Bool fixWinding) const
 {
@@ -166,10 +174,6 @@ Face& Polytope::findClosestFace()
 				index = i;
 				minDistance = face.distance(*this);
 			}
-			else
-			{
-				std::cout << "origin not in face" << std::endl;
-			}
 		}
 	}
 
@@ -212,6 +216,8 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		return false;
 	}
 
+	ANKI_ASSERT(cface.dead() == false);
+
 	//
 	// First add the point to the polytope by spliting the cface.
 	// Don't fix winding to the new faces because it should be correct.
@@ -233,12 +239,11 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 	Array<Face*, 3> newFaces = {
 		&cface, &m_faces[m_faces.size() - 2], &m_faces[m_faces.size() - 1]};
 
-	//return true;
-
 	//
 	// Find other faces that hide the new support
 	//
-	Vector<Face*, StackAllocator<Face*>> badFaces(getAllocator());
+	auto alloc = getAllocator();
+	Vector<Face*, CollisionTempAllocator<Face*>> badFaces(alloc);
 	Bool badFacesVectorInitialized = false; // Opt
 
 	const Vec4& support = m_simplex[supportIdx].m_v;
@@ -255,7 +260,7 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		}
 
 		F32 dot = face.normal(*this).dot(support);
-		if(dot > getEpsilon<F32>())
+		if(dot - face.distance(*this) > 0.0)
 		{
 			if(!badFacesVectorInitialized)
 			{
@@ -274,8 +279,6 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		return true;
 	}
 
-	std::cout << "found bad faces " << badFaces.size() << std::endl;
-
 	//
 	// Out of the new 3 faces find those that share edges with the bad faces
 	//
@@ -312,8 +315,8 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 	// deleted faces
 	//
 	std::unordered_map<Edge, U, EdgeHasher, EdgeCompare, 
-		StackAllocator<std::pair<Edge, U>>> edgeMap(
-		10, EdgeHasher(), EdgeCompare(), getAllocator());
+		CollisionTempAllocator<std::pair<Edge, U>>> edgeMap(
+		10, EdgeHasher(), EdgeCompare(), alloc);
 
 	for(Face* face : badFaces)
 	{
@@ -337,7 +340,7 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 	//
 	// Get the edges that are in a loop
 	//
-	Vector<Edge, StackAllocator<Edge>> edgeLoopTmp(getAllocator());
+	Vector<Edge, CollisionTempAllocator<Edge>> edgeLoopTmp(alloc);
 	edgeLoopTmp.reserve(edgeMap.size());
 	U startEdge = MAX_U32;
 
@@ -354,15 +357,23 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		}
 	}
 
-	ANKI_ASSERT(startEdge != MAX_U32);
+	if(newFacesBadCount < 3)
+	{
+		// If all 3 faces are bad then their edges will not appear
+		ANKI_ASSERT(startEdge != MAX_U32);
+	}
+	else
+	{
+		startEdge = 0;
+	}
 	ANKI_ASSERT(edgeLoopTmp.size() > 2);
 
 	//
 	// Sort those edges to a continues loop starting from the edge with the 
 	// support
 	// 
-	Vector<Edge, StackAllocator<Edge>> edgeLoop(getAllocator());
-	edgeLoop.reserve(edgeMap.size());
+	Vector<Edge, CollisionTempAllocator<Edge>> edgeLoop(alloc);
+	edgeLoop.reserve(edgeMap.size() + 2);
 
 	edgeLoop.push_back(edgeLoopTmp[startEdge]); // First edge
 
@@ -378,16 +389,26 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		}
 	}
 
-	ANKI_ASSERT(edgeLoop[0].m_idx[0] == supportIdx);
-
 	ANKI_ASSERT(edgeLoop[0].m_idx[0] == edgeLoop.back().m_idx[1] 
 		&& "Edge loop is not closed");
 
+	if(newFacesBadCount == 3)
+	{
+		edgeLoop.emplace(edgeLoop.begin(), 
+			supportIdx, edgeLoop.front().m_idx[0], nullptr);
+
+		edgeLoop.emplace_back(edgeLoop.back().m_idx[1], supportIdx, nullptr);
+	}
+
+	ANKI_ASSERT(edgeLoop[0].m_idx[0] == supportIdx);
+
 	//
 	// Spawn faces from the edge loop
 	//
+	const U limit = edgeLoop.size() - 1;
 	Edge edge = edgeLoop[0];
-	for(U i = 1; i < edgeLoop.size() - 1; i++)
+
+	for(U i = 1; i < limit; i++)
 	{
 		ANKI_ASSERT(edge.m_idx[1] == edgeLoop[i].m_idx[0]);
 

+ 146 - 0
src/collision/Tests.cpp

@@ -0,0 +1,146 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/collision/Tests.h"
+#include "anki/collision/ConvexShape.h"
+#include "anki/collision/Plane.h"
+#include "anki/collision/CompoundShape.h"
+#include "anki/collision/Aabb.h"
+#include "anki/collision/Sphere.h"
+#include "anki/collision/LineSegment.h"
+#include "anki/collision/Obb.h"
+#include "anki/collision/GjkEpa.h"
+
+namespace anki {
+
+// Forward
+static U todo(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points);
+
+static U gjkEpa(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points);
+
+static U comp(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points);
+
+//==============================================================================
+static Array2d<
+	CollisionTester::TestCallback, 
+	static_cast<U>(CollisionShape::Type::COUNT),
+	static_cast<U>(CollisionShape::Type::COUNT)> 
+	cdMatrix = {{
+	{todo, todo, todo, todo, todo, todo},
+	{comp, comp, comp, comp, comp, comp},
+	{todo, todo, todo, gjkEpa, todo, gjkEpa},
+	{todo, todo, todo, gjkEpa, todo, gjkEpa},
+	{todo, todo, todo, todo, todo, todo},
+	{todo, todo, todo, gjkEpa, todo, gjkEpa}}};
+
+//==============================================================================
+static U todo(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points)
+{
+	ANKI_ASSERT(0 && "TODO");
+	return 0;
+}
+
+//==============================================================================
+static U gjkEpa(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points)
+{
+	GjkEpa epa(20, 20, 20);
+
+	ContactPoint cp;
+	Bool intersect = epa.intersect(
+		static_cast<const ConvexShape&>(a), 
+		static_cast<const ConvexShape&>(b),
+		cp,
+		self._getAllocator());
+
+	if(!intersect)
+	{
+		return 0;
+	}
+	else
+	{
+		points.push_back(cp);
+		return 1;
+	}
+}
+
+//==============================================================================
+static U comp(CollisionTester& self,
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points)
+{
+	class Vis: public CollisionShape::ConstVisitor
+	{
+	public:
+		CollisionTester* m_self;
+		CollisionTempVector<ContactPoint>* m_points;
+		U32 m_out;
+		const CollisionShape* m_b;
+
+		void visit(const LineSegment& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+
+		void visit(const Obb& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+
+		void visit(const Plane& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+
+		void visit(const Sphere& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+
+		void visit(const Aabb& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+
+		void visit(const CompoundShape& a)
+		{
+			m_out += m_self->test(a, *m_b, *m_points);
+		}
+	};
+
+	Vis vis;
+	vis.m_self = &self;
+	vis.m_points = &points;
+	vis.m_out = 0;
+	vis.m_b = &b;
+	a.accept(vis);
+
+	return vis.m_out;
+}
+
+//==============================================================================
+U CollisionTester::test(
+	const CollisionShape& a, const CollisionShape& b, 
+	CollisionTempVector<ContactPoint>& points)
+{
+	ANKI_ASSERT(&a != &b);
+
+	U i = static_cast<U>(a.getType());
+	U j = static_cast<U>(b.getType());
+
+	return cdMatrix[i][j](*this, a, b, points);
+}
+
+} // end namespace anki
+

+ 64 - 14
src/renderer/Dbg.cpp

@@ -191,13 +191,12 @@ void Dbg::run(GlJobChainHandle& jobs)
 		Mat3x4 rot1 = scene.findSceneNode("shape1").
 			getComponent<MoveComponent>().getWorldTransform().getRotation();
 
-
 		Aabb s0(pos0 - Vec4(1.0, 1.0, 2.0, 0.0), pos0 + Vec4(1.0, 1.0, 2.0, 0.0));
 		Obb s1(pos1, rot1, Vec4(1.0, 0.5, 2.5, 0.0));
 
 		CollisionDebugDrawer dr(m_drawer.get());
 
-		GjkEpa gjk(100, 100);
+		GjkEpa gjk(100, 100, 100);
 		ContactPoint cp;
 		StackAllocator<U8> alloc(
 			StackMemoryPool(allocAligned, nullptr, 1024 * 1024));
@@ -216,21 +215,29 @@ void Dbg::run(GlJobChainHandle& jobs)
 		s0.accept(dr);
 		s1.accept(dr);
 
+
+		if(intersect) {
+
+
+		if(1)
+		{
 		m_drawer->setModelMatrix(Mat4::getIdentity());
 		m_drawer->setColor(Vec4(0.0, 1.0, 0.0, 1.0));
-		m_drawer->begin();
+		m_drawer->begin(GL_LINES);
 		m_drawer->pushBackVertex(Vec3(0.0));
 		m_drawer->pushBackVertex(cp.m_normal.xyz() * cp.m_depth);
-		//m_drawer->pushBackVertex(cp.m_normal.xyz());
+		//m_drawer->pushBackVertex(cp.m_normal.xyz() * 2.0);
 		//m_drawer->pushBackVertex(gjk.m_faces[gjk.m_faceCount - 3].m_normal.xyz());
 		m_drawer->end();
+		}
 
-		if(1)
+#if 0
+		if(0)
 		{
 			m_drawer->setModelMatrix(Mat4::getIdentity());
 			m_drawer->setColor(Vec4(1.0));
 
-			m_drawer->begin();
+			m_drawer->begin(GL_LINES);
 			m_drawer->pushBackVertex(Vec3(-10, 0, 0));
 			m_drawer->pushBackVertex(Vec3(10, 0, 0));
 			m_drawer->pushBackVertex(Vec3(0, 0, -10));
@@ -268,7 +275,7 @@ void Dbg::run(GlJobChainHandle& jobs)
 			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setColor(Vec4(1.0, 0.0, 1.0, 1.0));
-			m_drawer->begin();
+			m_drawer->begin(GL_LINES);
 			Array<U, 12> idx = {{0, 1, 2, 1, 2, 3, 2, 3, 0, 3, 0, 1}};
 			for(U i = 0; i < idx.size(); i += 3)
 			{
@@ -287,7 +294,7 @@ void Dbg::run(GlJobChainHandle& jobs)
 			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.02);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setColor(Vec4(1.0, 1.0, 0.0, 1.0));
-			m_drawer->begin();
+			m_drawer->begin(GL_LINES);
 			for(U i = 0; i < gjk.m_poly->m_simplex.size() - 1; i++)
 			{
 				m_drawer->pushBackVertex(gjk.m_poly->m_simplex[i].m_v.xyz());
@@ -298,10 +305,9 @@ void Dbg::run(GlJobChainHandle& jobs)
 
 		if(1)
 		{
-			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.01);
+			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
 			m_drawer->setModelMatrix(m);
-			m_drawer->setColor(Vec4(1.0, 0.0, 1.0, 1.0));
-			m_drawer->begin();
+			m_drawer->begin(GL_TRIANGLES);
 
 			static U64 count = 0;
 
@@ -319,7 +325,7 @@ void Dbg::run(GlJobChainHandle& jobs)
 				//auto idx = gjk.m_faces[offset].m_idx;
 				auto idx = gjk.m_poly->m_faces[i].idx();
 
-				if(i % 2)
+				/*if(i % 2)
 				{
 					m = Mat4(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.01);
 				}
@@ -327,7 +333,7 @@ void Dbg::run(GlJobChainHandle& jobs)
 				{
 					m = Mat4(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
 				}
-				m_drawer->setModelMatrix(m);
+				m_drawer->setModelMatrix(m);*/
 
 				if(i == faceCount - 1)
 				{
@@ -340,11 +346,19 @@ void Dbg::run(GlJobChainHandle& jobs)
 
 				#define WHAT(i_) gjk.m_poly->m_simplex[idx[i_]].m_v.xyz()
 
+				m_drawer->setColor(Vec4(1.0, 0.0, 0.0, 1.0));
 				m_drawer->pushBackVertex(WHAT(0));
+				m_drawer->setColor(Vec4(0.0, 1.0, 0.0, 1.0));
 				m_drawer->pushBackVertex(WHAT(1));
-				m_drawer->pushBackVertex(WHAT(1));
+				m_drawer->setColor(Vec4(0.0, 0.0, 1.0, 1.0));
 				m_drawer->pushBackVertex(WHAT(2));
+
+
+				m_drawer->setColor(Vec4(1.0, 0.0, 0.0, 1.0) / 3);
 				m_drawer->pushBackVertex(WHAT(2));
+				m_drawer->setColor(Vec4(0.0, 1.0, 0.0, 1.0) / 3);
+				m_drawer->pushBackVertex(WHAT(1));
+				m_drawer->setColor(Vec4(0.0, 0.0, 1.0, 1.0) / 3);
 				m_drawer->pushBackVertex(WHAT(0));
 
 				#undef WHAT
@@ -353,6 +367,37 @@ void Dbg::run(GlJobChainHandle& jobs)
 			m_drawer->end();
 		}
 
+		if(0)
+		{
+			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
+			m_drawer->setModelMatrix(m);
+			m_drawer->begin(GL_LINES);
+			m_drawer->setColor(Vec4(1.));
+
+			m_drawer->pushBackVertex(Vec3(0.));
+			m_drawer->pushBackVertex(gjk.m_poly->m_simplex.back().m_v.xyz() * 1.1);
+			
+		}
+
+		if(0)
+		{
+
+			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
+			m_drawer->setModelMatrix(m);
+			m_drawer->begin(GL_LINES);
+			m_drawer->setColor(Vec4(1.));
+
+			Vec4 support = gjk.m_poly->m_simplex.back().m_v;
+			Vec4 normal = gjk.m_poly->m_faces[3].normal(*gjk.m_poly);
+
+			std::cout << normal.dot(support) << std::endl;
+
+			m_drawer->pushBackVertex(Vec3(0.));
+			m_drawer->pushBackVertex(
+				 normal.xyz() * 2.1);
+			
+		}
+
 
 		/*m_drawer->setColor(Vec4(0.0, 1.0, 0.0, 1.0));
 		m_drawer->setModelMatrix(Mat4::getIdentity());
@@ -362,6 +407,11 @@ void Dbg::run(GlJobChainHandle& jobs)
 		m_drawer->pushBackVertex(gjk.m_b.xyz());
 		m_drawer->pushBackVertex(gjk.m_c.xyz());
 		m_drawer->end();*/
+
+		alloc.getMemoryPool().reset();
+#endif
+
+		} // intersect
 	}
 #endif
 

+ 74 - 24
src/renderer/DebugDrawer.cpp

@@ -31,9 +31,10 @@ DebugDrawer::DebugDrawer()
 		{m_vert->getGlProgram(), m_frag->getGlProgram()});
 
 	m_vertBuff = GlBufferHandle(jobs, GL_ARRAY_BUFFER, 
-		sizeof(m_clientVerts), GL_DYNAMIC_STORAGE_BIT);
+		sizeof(m_clientLineVerts), GL_DYNAMIC_STORAGE_BIT);
 
-	m_vertexPointer = 0;
+	m_lineVertCount = 0;
+	m_triVertCount = 0;
 	m_mMat.setIdentity();
 	m_vpMat.setIdentity();
 	m_mvpMat.setIdentity();
@@ -61,34 +62,72 @@ void DebugDrawer::setViewProjectionMatrix(const Mat4& m)
 }
 
 //==============================================================================
-void DebugDrawer::begin()
+void DebugDrawer::begin(GLenum primitive)
 {
-	// Do nothing. Keep for compatibility
+	ANKI_ASSERT(primitive == GL_TRIANGLES || primitive == GL_LINES);
+	m_primitive = primitive;
 }
 
 //==============================================================================
 void DebugDrawer::end()
 {
-	if(m_vertexPointer % 2 != 0)
+	if(m_primitive == GL_LINES)
 	{
-		pushBackVertex(Vec3(0.0));
-		ANKI_LOGW("Forgot to close the line loop");
+		if(m_lineVertCount % 2 != 0)
+		{
+			pushBackVertex(Vec3(0.0));
+			ANKI_LOGW("Forgot to close the line loop");
+		}
+	}
+	else
+	{
+		if(m_triVertCount % 3 != 0)
+		{
+			pushBackVertex(Vec3(0.0));
+			pushBackVertex(Vec3(0.0));
+			ANKI_LOGW("Forgot to close the line loop");
+		}
 	}
 }
 
 //==============================================================================
 void DebugDrawer::flush()
 {
-	if(m_vertexPointer == 0)
+	flushInternal(GL_LINES);
+	flushInternal(GL_TRIANGLES);
+}
+
+//==============================================================================
+void DebugDrawer::flushInternal(GLenum primitive)
+{
+	if((primitive == GL_LINES && m_lineVertCount == 0)
+		|| (primitive == GL_TRIANGLES && m_triVertCount == 0))
 	{
 		// Early exit
 		return;
 	}
 
-	GlClientBufferHandle tmpBuff(m_jobs, sizeof(m_clientVerts), nullptr);
-	memcpy(tmpBuff.getBaseAddress(), &m_clientVerts[0], sizeof(m_clientVerts));
+	U clientVerts;
+	void* vertBuff;
+	if(primitive == GL_LINES)
+	{
+		clientVerts = m_lineVertCount;
+		vertBuff = &m_clientLineVerts[0];
+		m_lineVertCount = 0;
+	}
+	else
+	{
+		clientVerts = m_triVertCount;
+		vertBuff = &m_clientTriVerts[0];
+		m_triVertCount = 0;
+	}
+
+	U size = sizeof(Vertex) * clientVerts;
 
-	m_vertBuff.write(m_jobs, tmpBuff, 0, 0, sizeof(m_clientVerts));
+	GlClientBufferHandle tmpBuff(m_jobs, size, nullptr);
+	memcpy(tmpBuff.getBaseAddress(), vertBuff, size);
+
+	m_vertBuff.write(m_jobs, tmpBuff, 0, 0, size);
 
 	m_ppline.bind(m_jobs);
 
@@ -98,22 +137,33 @@ void DebugDrawer::flush()
 	m_vertBuff.bindVertexBuffer(m_jobs, 
 		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
 
-	GlDrawcallArrays dc(GL_LINES, m_vertexPointer);
+	GlDrawcallArrays dc(primitive, clientVerts);
 
 	dc.draw(m_jobs);
-
-	m_vertexPointer = 0;
 }
 
 //==============================================================================
 void DebugDrawer::pushBackVertex(const Vec3& pos)
 {
-	m_clientVerts[m_vertexPointer].m_position = m_mvpMat * Vec4(pos, 1.0);
-	m_clientVerts[m_vertexPointer].m_color = Vec4(m_crntCol, 1.0);
+	U32* vertCount;
+	Vertex* vertBuff;
+	if(m_primitive == GL_LINES)
+	{
+		vertCount = &m_lineVertCount;
+		vertBuff = &m_clientLineVerts[0];
+	}
+	else
+	{
+		vertCount = &m_triVertCount;
+		vertBuff = &m_clientTriVerts[0];
+	}
+
+	vertBuff[*vertCount].m_position = m_mvpMat * Vec4(pos, 1.0);
+	vertBuff[*vertCount].m_color = Vec4(m_crntCol, 1.0);
 
-	++m_vertexPointer;
+	++(*vertCount);
 
-	if(m_vertexPointer == MAX_POINTS_PER_DRAW)
+	if(*vertCount == MAX_POINTS_PER_DRAW)
 	{
 		flush();
 	}
@@ -123,7 +173,7 @@ void DebugDrawer::pushBackVertex(const Vec3& pos)
 void DebugDrawer::drawLine(const Vec3& from, const Vec3& to, const Vec4& color)
 {
 	setColor(color);
-	begin();
+	begin(GL_LINES);
 		pushBackVertex(from);
 		pushBackVertex(to);
 	end();
@@ -143,7 +193,7 @@ void DebugDrawer::drawGrid()
 
 	setColor(col0);
 
-	begin();
+	begin(GL_LINES);
 
 	for(U x = - NUM / 2 * SPACE; x < NUM / 2 * SPACE; x += SPACE)
 	{
@@ -228,7 +278,7 @@ void DebugDrawer::drawSphere(F32 radius, I complexity)
 	setModelMatrix(m_mMat * Mat4(Vec4(0.0, 0.0, 0.0, 1.0), 
 		Mat3::getIdentity(), radius));
 
-	begin();
+	begin(GL_LINES);
 	for(const Vec3& p : *sphereLines)
 	{
 		pushBackVertex(p);
@@ -261,7 +311,7 @@ void DebugDrawer::drawCube(F32 size)
 		0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 
 		6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7}};
 
-	begin();
+	begin(GL_LINES);
 		for(U32 id : indeces)
 		{
 			pushBackVertex(points[id]);
@@ -314,7 +364,7 @@ void CollisionDebugDrawer::visit(const Plane& plane)
 void CollisionDebugDrawer::visit(const LineSegment& ls)
 {
 	m_dbg->setModelMatrix(Mat4::getIdentity());
-	m_dbg->begin();
+	m_dbg->begin(GL_LINES);
 	m_dbg->pushBackVertex(ls.getOrigin().xyz());
 	m_dbg->pushBackVertex((ls.getOrigin() + ls.getDirection()).xyz());
 	m_dbg->end();
@@ -369,7 +419,7 @@ void CollisionDebugDrawer::visit(const Frustum& f)
 			const U32 indeces[] = {0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 2,
 				3, 3, 4, 4, 1};
 
-			m_dbg->begin();
+			m_dbg->begin(GL_LINES);
 			for(U32 i = 0; i < sizeof(indeces) / sizeof(U32); i++)
 			{
 				m_dbg->pushBackVertex(points[indeces[i]]);

+ 3 - 1
src/resource/ProgramPrePreprocessor.cpp

@@ -66,8 +66,10 @@ void ProgramPrePreprocessor::parseFileForPragmas(
 	}
 
 	// load file in lines
+	String txt;
 	StringList lines;
-	File(filename.c_str(), File::OpenFlag::READ).readAllTextLines(lines);
+	File(filename.c_str(), File::OpenFlag::READ).readAllText(txt);
+	lines = StringList::splitString(txt.c_str(), '\n');
 	if(lines.size() < 1)
 	{
 		throw ANKI_EXCEPTION("File is empty: %s", filename.c_str());

+ 7 - 75
src/util/File.cpp

@@ -308,13 +308,11 @@ void File::read(void* buff, PtrSize size)
 }
 
 //==============================================================================
-void File::readAllText(String& txt)
+PtrSize File::getSize()
 {
 	ANKI_ASSERT(m_file);
 	ANKI_ASSERT(m_flags != OpenFlag::NONE);
-	ANKI_ASSERT((m_flags & OpenFlag::BINARY) == OpenFlag::NONE 
-		&& "Should not be binary file");
-	ANKI_ASSERT((m_flags & OpenFlag::READ) != OpenFlag::NONE);
+	PtrSize out;
 
 	if(m_type == Type::C)
 	{
@@ -327,92 +325,26 @@ void File::readAllText(String& txt)
 		}
 		rewind((FILE*)m_file);
 
-		// Read and write
-		txt.resize(size + 1);
-		PtrSize readSize = fread(&txt[0], 1, size, (FILE*)m_file);
-		ANKI_ASSERT(readSize == (PtrSize)size);
-		txt[readSize] = '\0';
+		out = size;
 	}
 	else if(m_type == Type::ZIP)
 	{
-		I64 readSize;
 		ANKI_ASSERT(m_size != 0);
-
-		txt.resize(m_size + 1);
-		readSize = unzReadCurrentFile(m_file, &txt[0], m_size);
-
-		if(readSize == m_size)
-		{
-			txt[readSize] = '\0';
-		}
-		else
-		{
-			throw ANKI_EXCEPTION("unzReadCurrentFile() failed");
-		}
+		out = m_size;
 	}
 #if ANKI_OS == ANKI_OS_ANDROID
 	else if(m_type == Type::SPECIAL)
 	{
-		PtrSize size = AAsset_getLength((AAsset*)m_file);
-		AAsset_seek((AAsset*)m_file, 0, SEEK_SET);
-
-		txt.resize(size + 1);
-		I readSize = AAsset_read((AAsset*)m_file, &txt[0], size);
-		ANKI_ASSERT((PtrSize)readSize == size);
-
-		txt[readSize] = '\0';
+		out = AAsset_getLength((AAsset*)m_file);
 	}
 #endif
 	else
 	{
 		ANKI_ASSERT(0);
 	}
-}
-
-//==============================================================================
-void File::readAllTextLines(StringList& lines)
-{
-	ANKI_ASSERT(m_file);
-	ANKI_ASSERT(m_flags != OpenFlag::NONE);
-	ANKI_ASSERT((m_flags & OpenFlag::BINARY) == OpenFlag::NONE 
-		&& "Should not be binary file");
-	ANKI_ASSERT((m_flags & OpenFlag::READ) != OpenFlag::NONE);
-
-	if(m_type == Type::C)
-	{
-		char line[1024];
 
-		while(fgets(line, sizeof(line), (FILE*)m_file))
-		{
-			I len = strlen(line);
-
-			if(len != sizeof(line) - 1)
-			{
-				// line is big enough
-
-				line[len - 1] = '\0';
-				lines.push_back(line);
-			}
-			else
-			{
-				throw ANKI_EXCEPTION("Line bigger than temp buffer");
-			}			
-		}
-	}
-	else if(m_type == Type::ZIP
-#if ANKI_OS == ANKI_OS_ANDROID
-		|| m_type & Type::SPECIAL
-#endif
-		)
-	{
-		String txt;
-		readAllText(txt);
-		lines = StringList::splitString(txt.c_str(), '\n');
-	}
-	else
-	{
-		ANKI_ASSERT(0);
-	}
+	ANKI_ASSERT(out != 0);
+	return out;
 }
 
 //==============================================================================

+ 17 - 0
src/util/Memory.cpp

@@ -486,6 +486,23 @@ U32 StackMemoryPool::getUsersCount() const
 	return m_impl->m_refcount.load();
 }
 
+//==============================================================================
+StackMemoryPool::Snapshot StackMemoryPool::getShapshot() const
+{
+	ANKI_ASSERT(m_impl != nullptr);
+	return m_impl->m_top.load();
+}
+
+//==============================================================================
+void StackMemoryPool::resetUsingSnapshot(Snapshot s)
+{
+	ANKI_ASSERT(m_impl != nullptr);
+	ANKI_ASSERT(static_cast<U8*>(s) >= m_impl->m_memory);
+	ANKI_ASSERT(static_cast<U8*>(s) < m_impl->m_memory + m_impl->m_memsize);
+
+	m_impl->m_top.store(static_cast<U8*>(s));
+}
+
 //==============================================================================
 // ChainMemoryPool                                                             =
 //==============================================================================

+ 6 - 2
testapp/Main.cpp

@@ -329,9 +329,13 @@ void init()
 
 	horse = scene.newSceneNode<ModelNode>("shape1", 
 		"models/collision_test/Cube.001_Material_001-material.ankimdl");
-	horse->setLocalTransform(Transform(Vec4(2.1, 2, 3.2, 0), 
-		Mat3x4(Euler(toRad(-20.0), toRad(40.0), toRad(15.0))),
+	horse->setLocalTransform(Transform(Vec4(3.1, 2, 0.2, 0), 
+		Mat3x4(Euler(toRad(-13.0), toRad(90.0), toRad(2.0))),
 		0.01));
+
+	horse->setLocalRotation(Mat3x4(0.135899, -0.534728, 0.834033, 0.000000,
+		0.091205, 0.845038, 0.526900, 0.000000 ,
+		-0.986537, 0.004463, 0.163603, 0.000000));
 }
 
 //==============================================================================