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:
 public:
 	/// Collision shape type
 	/// Collision shape type
+	/// @note WARNING: Order is important
 	enum class Type: U8
 	enum class Type: U8
 	{
 	{
-		LINE_SEG,
 		PLANE,
 		PLANE,
-		SPHERE,
+		COMPOUND,
 		AABB,
 		AABB,
+		SPHERE,
+		LINE_SEG,
 		OBB,
 		OBB,
-		COMPOUND
+		COUNT
 	};
 	};
 
 
 	/// Generic mutable visitor
 	/// Generic mutable visitor

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

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

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

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

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

@@ -9,7 +9,6 @@
 #include "anki/collision/Common.h"
 #include "anki/collision/Common.h"
 
 
 namespace anki {
 namespace anki {
-namespace detail {
 
 
 /// @addtogroup collision
 /// @addtogroup collision
 /// @{
 /// @{
@@ -18,27 +17,43 @@ namespace detail {
 /// shapes
 /// shapes
 /// @code
 /// @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
 /// @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
 } // end namespace anki
 
 
 #endif
 #endif

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

@@ -43,7 +43,7 @@ public:
 
 
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
 	/// @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 end(); ///< Draws
 	void pushBackVertex(const Vec3& pos); ///< Something like glVertex
 	void pushBackVertex(const Vec3& pos); ///< Something like glVertex
 	/// Something like glColor
 	/// Something like glColor
@@ -80,10 +80,13 @@ private:
 	Mat4 m_mMat;
 	Mat4 m_mMat;
 	Mat4 m_vpMat;
 	Mat4 m_vpMat;
 	Mat4 m_mvpMat; ///< Optimization
 	Mat4 m_mvpMat; ///< Optimization
-	U32 m_vertexPointer;
+	U32 m_lineVertCount;
+	U32 m_triVertCount;
 	Vec3 m_crntCol;
 	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;
 	GlBufferHandle m_vertBuff;
 
 
@@ -91,6 +94,8 @@ private:
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// from sphere complexity it returns a vector of lines (Vec3s in
 	/// pairs)
 	/// pairs)
 	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
 	std::unordered_map<U32, Vector<Vec3>> m_complexityToPreCalculatedSphere;
+
+	void flushInternal(GLenum primitive);
 };
 };
 
 
 /// Contains methods to render the collision shapes
 /// 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);
 	void read(void* buff, PtrSize size);
 
 
 	/// Read all the contents of a text file
 	/// 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 
 	/// Read 32bit unsigned integer. Set the endianness if the file's 
 	/// endianness is different from the machine's
 	/// endianness is different from the machine's
@@ -180,6 +185,9 @@ private:
 	/// Open an Android file
 	/// Open an Android file
 	void openAndroidFile(const char* filename, OpenFlag flags);
 	void openAndroidFile(const char* filename, OpenFlag flags);
 #endif
 #endif
+
+	/// The file should be open
+	PtrSize getSize();
 };
 };
 
 
 /// Return true if directory exists?
 /// Return true if directory exists?

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

@@ -104,6 +104,9 @@ class StackMemoryPool
 	friend class ChainMemoryPool;
 	friend class ChainMemoryPool;
 
 
 public:
 public:
+	/// The type of the pool's snapshot
+	using Snapshot = void*;
+
 	/// Default constructor
 	/// Default constructor
 	StackMemoryPool()
 	StackMemoryPool()
 		: m_impl(nullptr)
 		: m_impl(nullptr)
@@ -161,6 +164,16 @@ public:
 	/// Get the number of users for this pool
 	/// Get the number of users for this pool
 	U32 getUsersCount() const;
 	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:
 private:
 	// Forward. Hide the implementation because Memory.h is the base of other
 	// Forward. Hide the implementation because Memory.h is the base of other
 	// files and should not include them
 	// 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>>;
 using String = BasicString<char, std::allocator<char>>;
 
 
-
 /// Trim a string
 /// Trim a string
 /// Remove the @p what from the front and back of @p str
 /// Remove the @p what from the front and back of @p str
 template<typename TString>
 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,
 Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
-	ContactPoint& contact, StackAllocator<U8>& alloc)
+	ContactPoint& contact, CollisionTempAllocator<U8>& alloc)
 {
 {
 	// Do the intersection test
 	// Do the intersection test
 	Gjk gjk;
 	Gjk gjk;
@@ -254,11 +254,9 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 	// Init polytope
 	// Init polytope
 	detail::Polytope* poly = alloc.newInstance<detail::Polytope>(
 	detail::Polytope* poly = alloc.newInstance<detail::Polytope>(
 		alloc, m_maxSimplexSize, m_maxFaceCount);
 		alloc, m_maxSimplexSize, m_maxFaceCount);
-	m_poly = poly;
+	//m_poly = poly;
 	poly->init(gjk.m_simplex);
 	poly->init(gjk.m_simplex);
 
 
-	std::cout << "-----------------------" << std::endl;
-
 	U iterations = 0;
 	U iterations = 0;
 	while(1) 
 	while(1) 
 	{
 	{
@@ -278,8 +276,13 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 			//|| m_faceCount == m_faces.size() - 2
 			//|| m_faceCount == m_faces.size() - 2
 			//|| m_count == m_simplexArr.size() - 1
 			//|| m_count == m_simplexArr.size() - 1
 			//|| pIdx != m_count
 			//|| pIdx != m_count
-			|| iterations == 5)
+			|| iterations == 10)
 		{
 		{
+			if(iterations == 10)
+			{
+				std::cout << "too many iterations" << std::endl;
+			}
+
 			/*if(pIdx != m_count)
 			/*if(pIdx != m_count)
 			{
 			{
 				contact.m_normal = m_faces[prevFaceIndex].m_normal;
 				contact.m_normal = m_faces[prevFaceIndex].m_normal;
@@ -305,6 +308,8 @@ Bool GjkEpa::intersect(const ConvexShape& shape0, const ConvexShape& shape1,
 		++iterations;
 		++iterations;
 	}
 	}
 
 
+	alloc.deleteInstance(poly);
+
 	return true;
 	return true;
 }
 }
 
 

+ 40 - 19
src/collision/GjkEpaInternal.cpp

@@ -20,6 +20,14 @@ static inline std::ostream& operator<<(std::ostream& os, const Edge& e)
 // Face                                                                        =
 // 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
 const Vec4& Face::normal(Polytope& poly, Bool fixWinding) const
 {
 {
@@ -166,10 +174,6 @@ Face& Polytope::findClosestFace()
 				index = i;
 				index = i;
 				minDistance = face.distance(*this);
 				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;
 		return false;
 	}
 	}
 
 
+	ANKI_ASSERT(cface.dead() == false);
+
 	//
 	//
 	// First add the point to the polytope by spliting the cface.
 	// First add the point to the polytope by spliting the cface.
 	// Don't fix winding to the new faces because it should be correct.
 	// 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 = {
 	Array<Face*, 3> newFaces = {
 		&cface, &m_faces[m_faces.size() - 2], &m_faces[m_faces.size() - 1]};
 		&cface, &m_faces[m_faces.size() - 2], &m_faces[m_faces.size() - 1]};
 
 
-	//return true;
-
 	//
 	//
 	// Find other faces that hide the new support
 	// 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
 	Bool badFacesVectorInitialized = false; // Opt
 
 
 	const Vec4& support = m_simplex[supportIdx].m_v;
 	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);
 		F32 dot = face.normal(*this).dot(support);
-		if(dot > getEpsilon<F32>())
+		if(dot - face.distance(*this) > 0.0)
 		{
 		{
 			if(!badFacesVectorInitialized)
 			if(!badFacesVectorInitialized)
 			{
 			{
@@ -274,8 +279,6 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 		return true;
 		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
 	// 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
 	// deleted faces
 	//
 	//
 	std::unordered_map<Edge, U, EdgeHasher, EdgeCompare, 
 	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)
 	for(Face* face : badFaces)
 	{
 	{
@@ -337,7 +340,7 @@ Bool Polytope::expand(Face& cface, U supportIdx)
 	//
 	//
 	// Get the edges that are in a loop
 	// Get the edges that are in a loop
 	//
 	//
-	Vector<Edge, StackAllocator<Edge>> edgeLoopTmp(getAllocator());
+	Vector<Edge, CollisionTempAllocator<Edge>> edgeLoopTmp(alloc);
 	edgeLoopTmp.reserve(edgeMap.size());
 	edgeLoopTmp.reserve(edgeMap.size());
 	U startEdge = MAX_U32;
 	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);
 	ANKI_ASSERT(edgeLoopTmp.size() > 2);
 
 
 	//
 	//
 	// Sort those edges to a continues loop starting from the edge with the 
 	// Sort those edges to a continues loop starting from the edge with the 
 	// support
 	// 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
 	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] 
 	ANKI_ASSERT(edgeLoop[0].m_idx[0] == edgeLoop.back().m_idx[1] 
 		&& "Edge loop is not closed");
 		&& "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
 	// Spawn faces from the edge loop
 	//
 	//
+	const U limit = edgeLoop.size() - 1;
 	Edge edge = edgeLoop[0];
 	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]);
 		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").
 		Mat3x4 rot1 = scene.findSceneNode("shape1").
 			getComponent<MoveComponent>().getWorldTransform().getRotation();
 			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));
 		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));
 		Obb s1(pos1, rot1, Vec4(1.0, 0.5, 2.5, 0.0));
 
 
 		CollisionDebugDrawer dr(m_drawer.get());
 		CollisionDebugDrawer dr(m_drawer.get());
 
 
-		GjkEpa gjk(100, 100);
+		GjkEpa gjk(100, 100, 100);
 		ContactPoint cp;
 		ContactPoint cp;
 		StackAllocator<U8> alloc(
 		StackAllocator<U8> alloc(
 			StackMemoryPool(allocAligned, nullptr, 1024 * 1024));
 			StackMemoryPool(allocAligned, nullptr, 1024 * 1024));
@@ -216,21 +215,29 @@ void Dbg::run(GlJobChainHandle& jobs)
 		s0.accept(dr);
 		s0.accept(dr);
 		s1.accept(dr);
 		s1.accept(dr);
 
 
+
+		if(intersect) {
+
+
+		if(1)
+		{
 		m_drawer->setModelMatrix(Mat4::getIdentity());
 		m_drawer->setModelMatrix(Mat4::getIdentity());
 		m_drawer->setColor(Vec4(0.0, 1.0, 0.0, 1.0));
 		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(Vec3(0.0));
 		m_drawer->pushBackVertex(cp.m_normal.xyz() * cp.m_depth);
 		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->pushBackVertex(gjk.m_faces[gjk.m_faceCount - 3].m_normal.xyz());
 		m_drawer->end();
 		m_drawer->end();
+		}
 
 
-		if(1)
+#if 0
+		if(0)
 		{
 		{
 			m_drawer->setModelMatrix(Mat4::getIdentity());
 			m_drawer->setModelMatrix(Mat4::getIdentity());
 			m_drawer->setColor(Vec4(1.0));
 			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(10, 0, 0));
 			m_drawer->pushBackVertex(Vec3(10, 0, 0));
 			m_drawer->pushBackVertex(Vec3(0, 0, -10));
 			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);
 			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.0);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setColor(Vec4(1.0, 0.0, 1.0, 1.0));
 			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}};
 			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)
 			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);
 			Mat4 m(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), 1.02);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setModelMatrix(m);
 			m_drawer->setColor(Vec4(1.0, 1.0, 0.0, 1.0));
 			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++)
 			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());
 				m_drawer->pushBackVertex(gjk.m_poly->m_simplex[i].m_v.xyz());
@@ -298,10 +305,9 @@ void Dbg::run(GlJobChainHandle& jobs)
 
 
 		if(1)
 		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->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;
 			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_faces[offset].m_idx;
 				auto idx = gjk.m_poly->m_faces[i].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);
 					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 = 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)
 				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()
 				#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->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->pushBackVertex(WHAT(1));
+				m_drawer->setColor(Vec4(0.0, 0.0, 1.0, 1.0));
 				m_drawer->pushBackVertex(WHAT(2));
 				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->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));
 				m_drawer->pushBackVertex(WHAT(0));
 
 
 				#undef WHAT
 				#undef WHAT
@@ -353,6 +367,37 @@ void Dbg::run(GlJobChainHandle& jobs)
 			m_drawer->end();
 			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->setColor(Vec4(0.0, 1.0, 0.0, 1.0));
 		m_drawer->setModelMatrix(Mat4::getIdentity());
 		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_b.xyz());
 		m_drawer->pushBackVertex(gjk.m_c.xyz());
 		m_drawer->pushBackVertex(gjk.m_c.xyz());
 		m_drawer->end();*/
 		m_drawer->end();*/
+
+		alloc.getMemoryPool().reset();
+#endif
+
+		} // intersect
 	}
 	}
 #endif
 #endif
 
 

+ 74 - 24
src/renderer/DebugDrawer.cpp

@@ -31,9 +31,10 @@ DebugDrawer::DebugDrawer()
 		{m_vert->getGlProgram(), m_frag->getGlProgram()});
 		{m_vert->getGlProgram(), m_frag->getGlProgram()});
 
 
 	m_vertBuff = GlBufferHandle(jobs, GL_ARRAY_BUFFER, 
 	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_mMat.setIdentity();
 	m_vpMat.setIdentity();
 	m_vpMat.setIdentity();
 	m_mvpMat.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()
 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()
 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
 		// Early exit
 		return;
 		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);
 	m_ppline.bind(m_jobs);
 
 
@@ -98,22 +137,33 @@ void DebugDrawer::flush()
 	m_vertBuff.bindVertexBuffer(m_jobs, 
 	m_vertBuff.bindVertexBuffer(m_jobs, 
 		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
 		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
 
 
-	GlDrawcallArrays dc(GL_LINES, m_vertexPointer);
+	GlDrawcallArrays dc(primitive, clientVerts);
 
 
 	dc.draw(m_jobs);
 	dc.draw(m_jobs);
-
-	m_vertexPointer = 0;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void DebugDrawer::pushBackVertex(const Vec3& pos)
 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();
 		flush();
 	}
 	}
@@ -123,7 +173,7 @@ void DebugDrawer::pushBackVertex(const Vec3& pos)
 void DebugDrawer::drawLine(const Vec3& from, const Vec3& to, const Vec4& color)
 void DebugDrawer::drawLine(const Vec3& from, const Vec3& to, const Vec4& color)
 {
 {
 	setColor(color);
 	setColor(color);
-	begin();
+	begin(GL_LINES);
 		pushBackVertex(from);
 		pushBackVertex(from);
 		pushBackVertex(to);
 		pushBackVertex(to);
 	end();
 	end();
@@ -143,7 +193,7 @@ void DebugDrawer::drawGrid()
 
 
 	setColor(col0);
 	setColor(col0);
 
 
-	begin();
+	begin(GL_LINES);
 
 
 	for(U x = - NUM / 2 * SPACE; x < NUM / 2 * SPACE; x += SPACE)
 	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), 
 	setModelMatrix(m_mMat * Mat4(Vec4(0.0, 0.0, 0.0, 1.0), 
 		Mat3::getIdentity(), radius));
 		Mat3::getIdentity(), radius));
 
 
-	begin();
+	begin(GL_LINES);
 	for(const Vec3& p : *sphereLines)
 	for(const Vec3& p : *sphereLines)
 	{
 	{
 		pushBackVertex(p);
 		pushBackVertex(p);
@@ -261,7 +311,7 @@ void DebugDrawer::drawCube(F32 size)
 		0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 
 		0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 
 		6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7}};
 		6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7}};
 
 
-	begin();
+	begin(GL_LINES);
 		for(U32 id : indeces)
 		for(U32 id : indeces)
 		{
 		{
 			pushBackVertex(points[id]);
 			pushBackVertex(points[id]);
@@ -314,7 +364,7 @@ void CollisionDebugDrawer::visit(const Plane& plane)
 void CollisionDebugDrawer::visit(const LineSegment& ls)
 void CollisionDebugDrawer::visit(const LineSegment& ls)
 {
 {
 	m_dbg->setModelMatrix(Mat4::getIdentity());
 	m_dbg->setModelMatrix(Mat4::getIdentity());
-	m_dbg->begin();
+	m_dbg->begin(GL_LINES);
 	m_dbg->pushBackVertex(ls.getOrigin().xyz());
 	m_dbg->pushBackVertex(ls.getOrigin().xyz());
 	m_dbg->pushBackVertex((ls.getOrigin() + ls.getDirection()).xyz());
 	m_dbg->pushBackVertex((ls.getOrigin() + ls.getDirection()).xyz());
 	m_dbg->end();
 	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,
 			const U32 indeces[] = {0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 2,
 				3, 3, 4, 4, 1};
 				3, 3, 4, 4, 1};
 
 
-			m_dbg->begin();
+			m_dbg->begin(GL_LINES);
 			for(U32 i = 0; i < sizeof(indeces) / sizeof(U32); i++)
 			for(U32 i = 0; i < sizeof(indeces) / sizeof(U32); i++)
 			{
 			{
 				m_dbg->pushBackVertex(points[indeces[i]]);
 				m_dbg->pushBackVertex(points[indeces[i]]);

+ 3 - 1
src/resource/ProgramPrePreprocessor.cpp

@@ -66,8 +66,10 @@ void ProgramPrePreprocessor::parseFileForPragmas(
 	}
 	}
 
 
 	// load file in lines
 	// load file in lines
+	String txt;
 	StringList lines;
 	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)
 	if(lines.size() < 1)
 	{
 	{
 		throw ANKI_EXCEPTION("File is empty: %s", filename.c_str());
 		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_file);
 	ANKI_ASSERT(m_flags != OpenFlag::NONE);
 	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)
 	if(m_type == Type::C)
 	{
 	{
@@ -327,92 +325,26 @@ void File::readAllText(String& txt)
 		}
 		}
 		rewind((FILE*)m_file);
 		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)
 	else if(m_type == Type::ZIP)
 	{
 	{
-		I64 readSize;
 		ANKI_ASSERT(m_size != 0);
 		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
 #if ANKI_OS == ANKI_OS_ANDROID
 	else if(m_type == Type::SPECIAL)
 	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
 #endif
 	else
 	else
 	{
 	{
 		ANKI_ASSERT(0);
 		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();
 	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                                                             =
 // ChainMemoryPool                                                             =
 //==============================================================================
 //==============================================================================

+ 6 - 2
testapp/Main.cpp

@@ -329,9 +329,13 @@ void init()
 
 
 	horse = scene.newSceneNode<ModelNode>("shape1", 
 	horse = scene.newSceneNode<ModelNode>("shape1", 
 		"models/collision_test/Cube.001_Material_001-material.ankimdl");
 		"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));
 		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));
 }
 }
 
 
 //==============================================================================
 //==============================================================================