Explorar el Código

Some collision work

Panagiotis Christopoulos Charitos hace 11 años
padre
commit
e35112b95e

+ 5 - 0
include/anki/collision/Aabb.h

@@ -20,6 +20,11 @@ class Aabb: public ConvexShape
 public:
 	using Base = ConvexShape;
 
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::AABB;
+	}
+
 	Aabb()
 	:	Base(Type::AABB)
 	{}

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

@@ -26,10 +26,10 @@ public:
 	enum class Type: U8
 	{
 		PLANE,
+		LINE_SEG,
 		COMPOUND,
 		AABB,
 		SPHERE,
-		LINE_SEG,
 		OBB,
 		COUNT
 	};
@@ -64,39 +64,30 @@ public:
 		virtual void visit(const CompoundShape&) = 0;
 	};
 
-	/// @name Constructors & destructor
-	/// @{
 	CollisionShape(Type cid)
-		: m_cid(cid)
+	:	m_cid(cid)
 	{}
 
 	CollisionShape(const CollisionShape& b)
-		: m_cid(b.m_cid)
+	:	m_cid(b.m_cid)
 	{
 		operator=(b);
 	}
 
 	virtual ~CollisionShape()
 	{}
-	/// @}
 
-	/// @name Operators
-	/// @{
 	CollisionShape& operator=(const CollisionShape& b)
 	{
 		ANKI_ASSERT(b.m_cid == m_cid);
 		(void)b;
 		return *this;
 	}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	Type getType() const
 	{
 		return m_cid;
 	}
-	/// @}
 
 	/// If the collision shape intersects with the plane then the method
 	/// returns 0.0, else it returns the distance. If the distance is < 0.0

+ 33 - 18
include/anki/collision/CompoundShape.h

@@ -18,6 +18,11 @@ namespace anki {
 class CompoundShape: public CollisionShape, public NonCopyable
 {
 public:
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::COMPOUND;
+	}
+
 	CompoundShape();
 
 	/// Implements CollisionShape::testPlane
@@ -38,6 +43,9 @@ public:
 	/// The compound shape will not take ownership of the object
 	void addShape(CollisionShape* shape);
 
+	template<typename TFunc>
+	ANKI_USE_RESULT Error iterateShapes(TFunc f) const;
+
 private:
 	static const U SHAPES_PER_CHUNK_COUNT = 8;
 
@@ -49,32 +57,39 @@ private:
 	};
 
 	Chunk m_dflt;
+};
 
-	template<typename TFunc>
-	void iterateShapes(TFunc f) const
-	{
-		U count = 0;
-		const Chunk* chunk = &m_dflt;
+//==============================================================================
+template<typename TFunc>
+Error CompoundShape::iterateShapes(TFunc f) const
+{
+	Error err = ErrorCode::NONE;
+	U count = 0;
+	const Chunk* chunk = &m_dflt;
 
-		do
+	do
+	{
+		U idx = SHAPES_PER_CHUNK_COUNT;
+		while(idx-- != 0)
 		{
-			U idx = SHAPES_PER_CHUNK_COUNT;
-			while(idx-- != 0)
+			if(chunk->m_shapes[idx])
 			{
-				if(chunk->m_shapes[idx])
+				err = f(*const_cast<CollisionShape*>(chunk->m_shapes[idx]));
+				if(err)
 				{
-					f(*const_cast<CollisionShape*>(chunk->m_shapes[idx]));
-					++count;
+					return err;
 				}
+				++count;
 			}
+		}
 
-			chunk = chunk->m_next;
-		} while(chunk);
-	
-		ANKI_ASSERT(count > 0 && "Empty CompoundShape");
-		(void)count;
-	}
-};
+		chunk = chunk->m_next;
+	} while(chunk);
+
+	ANKI_ASSERT(count > 0 && "Empty CompoundShape");
+	(void)count;
+	return err;
+}
 /// @}
 
 } // end namespace anki

+ 94 - 0
include/anki/collision/ConvexHullShape.h

@@ -0,0 +1,94 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_COLLISION_CONVEX_HULL_SHAPE_H
+#define ANKI_COLLISION_CONVEX_HULL_SHAPE_H
+
+#include "anki/collision/ConvexShape.h"
+#include "anki/Math.h"
+
+namespace anki {
+
+/// @addtogroup collision
+/// @{
+
+/// Convex hull collision shape
+class ConvexHullShape: public ConvexShape
+{
+public:
+	using Base = ConvexShape;
+
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::CONVEX_HULL;
+	}
+
+	ConvexHullShape()
+	:	Base(Type::CONVEX_HULL)
+	{}
+
+	ConvexHullShape(ConvexHullShape&& b)
+	:	Base(Type::CONVEX_HULL)
+	{
+		*this = std::move(b);
+	}
+
+	ConvexHullShape(const ConvexHullShape& b) = delete;
+
+	~ConvexHullShape();
+
+	ConvexHullShape& operator=(const ConvexHullShape& b) = delete;
+
+	ConvexHullShape& operator=(ConvexHullShape&& b);
+
+	/// Calculate from a set of points. You have to call initStorage before
+	/// calling this method.
+	void setFromPointCloud(
+		const Vec3* buff, U count, PtrSize stride, PtrSize buffSize);
+
+	/// This function initializes the storage that holds the point cloud. This
+	/// method allocates a storage and the owner is the convex hull. 
+	/// @param alloc The allocator to use for the point cloud
+	/// @param pointCount The number of points
+	void initStorage(CollisionAllocator<U8>& alloc, U pointCount);
+
+	/// This function initializes the storage that holds the point cloud using
+	/// a predefined buffer. The convex hull is not the owner of the storage.
+	/// @param buffer The base of the storage buffer. Size should be 
+	///               @a pointCount * sizeof(Vec4)
+	/// @param pointCount The number of points
+	void initStorage(void* buffer, U pointCount);
+
+	/// Implements CollisionShape::accept
+	void accept(MutableVisitor& v)
+	{
+		v.visit(*this);
+	}
+	/// Implements CollisionShape::accept
+	void accept(ConstVisitor& v) const
+	{
+		v.visit(*this);
+	}
+
+	/// Implements CollisionShape::testPlane
+	F32 testPlane(const Transform& trf, const Plane& p) const;
+
+	/// Implements CollisionShape::computeAabb
+	void computeAabb(const Transform& trf, Aabb& aabb) const;
+
+	/// Implements ConvexShape::computeSupport
+	Vec4 computeSupport(const Vec4& dir) const;
+
+private:
+	Vec4* m_points = nullptr;
+	U32 m_pointsCount = 0;
+	CollisionAllocator<U8> m_alloc;
+	Bool8 m_ownsTheStorage = false;
+};
+/// @}
+
+} // end namespace anki
+
+#endif

+ 5 - 0
include/anki/collision/ConvexShape.h

@@ -38,6 +38,11 @@ public:
 
 	/// Get a support vector for the GJK algorithm
 	virtual Vec4 computeSupport(const Vec4& dir) const = 0;
+
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() >= Type::AABB && c.getType() <= Type::OBB;
+	}
 };
 /// @}
 

+ 8 - 3
include/anki/collision/Frustum.h

@@ -112,6 +112,7 @@ protected:
 
 	/// Used to check against the frustum
 	Array<Plane, (U)PlaneType::COUNT> m_planes;
+	Array<Plane, (U)PlaneType::COUNT> m_planesW;
 
 	/// Keep the transformation.
 	Transform m_trf = Transform::getIdentity(); 
@@ -122,7 +123,11 @@ protected:
 	/// Called when a viewing variable changes. It recalculates the planes and
 	/// the other variables.
 	/// @note It's const because it must be called on const methods.
-	virtual void recalculate() = 0;
+	virtual void recalculate(Bool planes, Bool other) = 0;
+
+	/// Update if dirty
+	void update() const;
+	void updateInternal();
 
 	/// Copy
 	Frustum& operator=(const Frustum& b);
@@ -217,7 +222,7 @@ private:
 	/// Implements Frustum::recalculate. Recalculates:
 	/// @li planes
 	/// @li line segments
-	void recalculate() override;
+	void recalculate(Bool planes, Bool other) override;
 };
 
 /// Frustum shape for orthographic cameras
@@ -327,7 +332,7 @@ private:
 	/// @}
 
 	/// Implements Frustum::recalculate. Recalculate @a m_planes and @a m_obb
-	void recalculate() override;
+	void recalculate(Bool planes, Bool other) override;
 };
 /// @}
 

+ 0 - 1
include/anki/collision/GjkEpaInternal.h

@@ -19,7 +19,6 @@ class Face;
 /// @addtogroup collision_internal
 /// @{
 
-
 /// Edge of a polytope
 class Edge
 {

+ 12 - 19
include/anki/collision/LineSegment.h

@@ -21,29 +21,29 @@ class LineSegment: public CollisionShape
 public:
 	using Base = CollisionShape;
 
-	/// @name Constructors
-	/// @{
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::LINE_SEG;
+	}
+
 	LineSegment()
-		:	Base(Type::LINE_SEG),
-			m_origin(0.0),
-			m_dir(0.0)
+	:	Base(Type::LINE_SEG),
+		m_origin(0.0),
+		m_dir(0.0)
 	{}
 
 	LineSegment(const Vec4& origin, const Vec4& direction)
-		:	Base(Type::LINE_SEG), 
-			m_origin(origin), 
-			m_dir(direction)
+	:	Base(Type::LINE_SEG), 
+		m_origin(origin), 
+		m_dir(direction)
 	{}
 
 	LineSegment(const LineSegment& b)
-		:	Base(Type::LINE_SEG)
+	:	Base(Type::LINE_SEG)
 	{
 		operator=(b);
 	}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	const Vec4& getOrigin() const
 	{
 		return m_origin;
@@ -73,10 +73,7 @@ public:
 	{
 		m_dir = x;
 	}
-	/// @}
 
-	/// @name Operators
-	/// @{
 	LineSegment& operator=(const LineSegment& b)
 	{
 		Base::operator=(b);
@@ -84,7 +81,6 @@ public:
 		m_dir = b.m_dir;
 		return *this;
 	}
-	/// @}
 
 	/// Implements CollisionShape::accept
 	void accept(MutableVisitor& v)
@@ -112,11 +108,8 @@ public:
 	LineSegment getTransformed(const Transform& transform) const;
 
 private:
-	/// @name Data
-	/// @{
 	Vec4 m_origin; ///< P0
 	Vec4 m_dir; ///< P1 = origin+dir so dir = P1-origin
-	/// @}
 };
 /// @}
 

+ 6 - 11
include/anki/collision/Obb.h

@@ -22,17 +22,17 @@ class Obb: public ConvexShape
 public:
 	using Base = ConvexShape;
 
-	/// @name Constructors
-	/// @{
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::OBB;
+	}
+
 	Obb();
 
 	Obb(const Obb& b);
 
 	Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend);
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	const Vec4& getCenter() const
 	{
 		return m_center;
@@ -77,12 +77,8 @@ public:
 		makeDirty();
 		m_extend = x;
 	}
-	/// @}
 
-	/// @name Operators
-	/// @{
 	Obb& operator=(const Obb& b);
-	/// @}
 
 	/// Implements CollisionShape::accept
 	void accept(MutableVisitor& v)
@@ -130,9 +126,8 @@ public:
 	/// our case)
 	Vec4 m_extend;
 
-	class 
+	struct 
 	{
-	public:
 		mutable Aabb m_aabb;
 		mutable Array<Vec4, 8> m_extremePoints;
 		mutable Bool8 m_dirtyAabb = true;

+ 8 - 13
include/anki/collision/Plane.h

@@ -20,17 +20,19 @@ class Plane: public CollisionShape
 public:
 	using Base = CollisionShape;
 
-	/// @name Constructors
-	/// @{
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::PLANE;
+	}
 
 	/// Default constructor
 	Plane()
-		: CollisionShape(Type::PLANE)
+	:	CollisionShape(Type::PLANE)
 	{}
 
 	/// Copy constructor
 	Plane(const Plane& b)
-		: CollisionShape(Type::PLANE)
+	:	CollisionShape(Type::PLANE)
 	{
 		operator=(b);
 	}
@@ -40,21 +42,18 @@ public:
 
 	/// @see setFrom3Points
 	Plane(const Vec3& p0, const Vec3& p1, const Vec3& p2)
-		: CollisionShape(Type::PLANE)
+	:	CollisionShape(Type::PLANE)
 	{
 		setFrom3Points(p0, p1, p2);
 	}
 
 	/// @see setFromPlaneEquation
 	Plane(F32 a, F32 b, F32 c, F32 d)
-		: CollisionShape(Type::PLANE)
+	:	CollisionShape(Type::PLANE)
 	{
 		setFromPlaneEquation(a, b, c, d);
 	}
-	/// @}
 
-	/// @name Operators
-	/// @{
 	Plane& operator=(const Plane& b)
 	{
 		Base::operator=(b);
@@ -62,10 +61,7 @@ public:
 		m_offset = b.m_offset;
 		return *this;
 	}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	const Vec4& getNormal() const
 	{
 		return m_normal;
@@ -91,7 +87,6 @@ public:
 	{
 		m_offset = x;
 	}
-	/// @}
 
 	/// Implements CollisionShape::accept
 	void accept(MutableVisitor& v)

+ 9 - 14
include/anki/collision/Sphere.h

@@ -20,31 +20,30 @@ class Sphere: public ConvexShape
 public:
 	using Base = ConvexShape;
 
-	/// @name Constructors
-	/// @{
+	static Bool classof(const CollisionShape& c)
+	{
+		return c.getType() == Type::SPHERE;
+	}
 
 	/// Default constructor
 	Sphere()
-		: Base(Type::SPHERE)
+	:	Base(Type::SPHERE)
 	{}
 
 	/// Copy constructor
 	Sphere(const Sphere& b)
-		: Base(Type::SPHERE)
+	:	Base(Type::SPHERE)
 	{
 		operator=(b);
 	}
 
 	/// Constructor
 	Sphere(const Vec4& center, F32 radius)
-		:	Base(Type::SPHERE), 
-			m_center(center), 
-			m_radius(radius)
+	:	Base(Type::SPHERE), 
+		m_center(center), 
+		m_radius(radius)
 	{}
-	/// @}
 
-	/// @name Accessors
-	/// @{
 	const Vec4& getCenter() const
 	{
 		return m_center;
@@ -74,10 +73,7 @@ public:
 	{
 		m_radius = x;
 	}
-	/// @}
 
-	/// @name Operators
-	/// @{
 	Sphere& operator=(const Sphere& b)
 	{
 		Base::operator=(b);
@@ -85,7 +81,6 @@ public:
 		m_radius = b.m_radius;
 		return *this;
 	}
-	/// @}
 
 	/// Implements CollisionShape::accept
 	void accept(MutableVisitor& v)

+ 10 - 0
include/anki/math/Vec.h

@@ -2155,6 +2155,16 @@ public:
 		return ((*this) * (1.0 - t)) + (v1 * t);
 	}
 
+	TV getAbs() const
+	{
+		TV out;
+		for(U i = 0; i < N; ++i)
+		{
+			out[i] = fabs<T>(m_arr[i]);
+		}
+		return out;
+	}
+
 	template<typename TAlloc>
 	StringBase<typename TAlloc::template rebind<char>::other> toString(
 		TAlloc alloc_) const

+ 3 - 0
include/anki/math/Vec4.h

@@ -179,6 +179,9 @@ void TVec4<F32>::Base::normalize();
 template<>
 TVec4<F32> TVec4<F32>::cross(const TVec4<F32>& b) const;
 
+template<>
+TVec4<F32> TVec4<F32>::Base::getAbs() const;
+
 #elif ANKI_SIMD == ANKI_SIMD_NEON
 
 #	error "TODO"

+ 8 - 0
include/anki/math/Vec4.inl.h

@@ -203,6 +203,14 @@ inline void TVec4<F32>::Base::normalize()
 	m_simd = _mm_mul_ps(m_simd, inverseNorm);
 }
 
+//==============================================================================
+template<>
+inline TVec4<F32> TVec4<F32>::Base::getAbs() const
+{
+	static const __m128 signMask = _mm_set1_ps(-0.0f);
+	return TVec4<F32>(_mm_andnot_ps(signMask, m_simd));	
+}
+
 #elif ANKI_SIMD == ANKI_SIMD_NEON
 
 //==============================================================================

+ 82 - 0
include/anki/util/Rtti.h

@@ -0,0 +1,82 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_UTIL_RTTI_H
+#define ANKI_UTIL_RTTI_H
+
+#include "anki/util/Assert.h"
+
+namespace anki {
+
+/// @addtogroup util_private
+/// @{
+template<typename T>
+struct ExtractType
+{
+	using Type = T;
+};
+
+template<typename T>
+struct ExtractType<const T&>
+{
+	using Type = T;
+};
+
+template<typename T>
+struct ExtractType<T&>
+{
+	using Type = T;
+};
+
+template<typename T>
+struct ExtractType<const T*>
+{
+	using Type = T;
+};
+
+template<typename T>
+struct ExtractType<T*>
+{
+	using Type = T;
+};
+/// @}
+
+/// @addtogroup util_misc
+/// @{
+
+/// Check if a class is of certain type.
+template<typename TTo, typename TFrom>
+inline Bool isa(TFrom& c)
+{
+	return TTo::classof(c);
+}
+
+/// Check if a class is of certain type.
+template<typename TTo, typename TFrom>
+inline Bool isa(TFrom* c)
+{
+	return TTo::classof(*c);
+}
+
+/// Custom dynamic cast.
+template<typename TTo, typename TFrom>
+inline TTo dcast(TFrom& c)
+{
+	ANKI_ASSERT(isa<typename ExtractType<TTo>::Type>(c));
+	return static_cast<TTo>(c);
+}
+
+/// Custom dynamic cast.
+template<typename TTo, typename TFrom>
+inline TTo dcast(TFrom* c)
+{
+	ANKI_ASSERT(isa<typename ExtractType<TTo>::Type>(c));
+	return static_cast<TTo>(c);
+}
+/// @}
+
+} // end namespace anki
+
+#endif

+ 1 - 1
shaders/IsLp.frag.glsl

@@ -348,7 +348,7 @@ void main()
 #if 0
 	if(pointLightsCount != 0)
 	{
-		out_color = vec3(0.5 / float(pointLightsCount));
+		out_color = vec3(0.05 * float(pointLightsCount));
 	}
 #endif
 }

+ 15 - 5
src/collision/CompoundShape.cpp

@@ -22,12 +22,14 @@ F32 CompoundShape::testPlane(const Plane& p) const
 	F32 min = MAX_F32;
 	F32 max = MIN_F32;
 
-	iterateShapes([&](const CollisionShape& cs)
+	Error err = iterateShapes([&](const CollisionShape& cs) -> Error
 	{
 		F32 a = cs.testPlane(p);
 		min = std::min(min, a);
 		max = std::max(max, a);
+		return ErrorCode::NONE;
 	});
+	(void)err;
 
 	if(min > 0.0 && max > 0.0)
 	{
@@ -44,28 +46,34 @@ F32 CompoundShape::testPlane(const Plane& p) const
 //==============================================================================
 void CompoundShape::accept(MutableVisitor& v)
 {
-	iterateShapes([&](CollisionShape& cs)
+	Error err = iterateShapes([&](CollisionShape& cs) -> Error
 	{
 		cs.accept(v);
+		return ErrorCode::NONE;
 	});
+	(void)err;
 }
 
 //==============================================================================
 void CompoundShape::accept(ConstVisitor& v) const
 {
-	iterateShapes([&](const CollisionShape& cs)
+	Error err = iterateShapes([&](const CollisionShape& cs) -> Error
 	{
 		cs.accept(v);
+		return ErrorCode::NONE;
 	});
+	(void)err;
 }
 
 //==============================================================================
 void CompoundShape::transform(const Transform& trf)
 {
-	iterateShapes([&](CollisionShape& cs)
+	Error err = iterateShapes([&](CollisionShape& cs) -> Error
 	{
 		cs.transform(trf);
+		return ErrorCode::NONE;
 	});
+	(void)err;
 }
 
 //==============================================================================
@@ -73,7 +81,7 @@ void CompoundShape::computeAabb(Aabb& out) const
 {
 	Vec4 min(Vec3(MAX_F32), 0.0), max(Vec3(MIN_F32), 0.0);
 
-	iterateShapes([&](const CollisionShape& cs)
+	Error err = iterateShapes([&](const CollisionShape& cs) -> Error
 	{
 		Aabb aabb;
 		cs.computeAabb(aabb);
@@ -83,7 +91,9 @@ void CompoundShape::computeAabb(Aabb& out) const
 			min[i] = std::min(min[i], aabb.getMin()[i]);
 			max[i] = std::max(max[i], aabb.getMax()[i]);
 		}
+		return ErrorCode::NONE;
 	});
+	(void)err;
 
 	out.setMin(min);
 	out.setMax(max);

+ 124 - 107
src/collision/Frustum.cpp

@@ -21,6 +21,7 @@ Frustum& Frustum::operator=(const Frustum& b)
 	m_near = b.m_near;
 	m_far = b.m_far;
 	m_planes = b.m_planes;
+	m_planesW = b.m_planesW;
 	m_trf = b.m_trf;
 	m_frustumDirty = b.m_frustumDirty;
 	return *this;
@@ -29,67 +30,37 @@ Frustum& Frustum::operator=(const Frustum& b)
 //==============================================================================
 void Frustum::accept(MutableVisitor& v)
 {
-	if(m_frustumDirty)
-	{
-		// Force recalculation and tranform
-		resetTransform(m_trf);
-	}
-
+	update();
 	CompoundShape::accept(v);
 }
 
 //==============================================================================
 void Frustum::accept(ConstVisitor& v) const
 {
-	Frustum& self = *const_cast<Frustum*>(this);
-
-	if(self.m_frustumDirty)
-	{
-		// Force recalculation and tranform
-		self.resetTransform(m_trf);
-	}
-
+	update();
 	CompoundShape::accept(v);
 }
 
 //==============================================================================
 F32 Frustum::testPlane(const Plane& p) const
 {
-	Frustum& self = *const_cast<Frustum*>(this);
-
-	if(self.m_frustumDirty)
-	{
-		// Force recalculation and tranform
-		self.resetTransform(m_trf);
-	}
-
+	update();
 	return CompoundShape::testPlane(p);
 }
 
 //==============================================================================
 void Frustum::computeAabb(Aabb& aabb) const
 {
-	Frustum& self = *const_cast<Frustum*>(this);
-
-	if(self.m_frustumDirty)
-	{
-		// Force recalculation and tranform
-		self.resetTransform(m_trf);
-	}
-
+	update();
 	CompoundShape::computeAabb(aabb);
 }
 
 //==============================================================================
 Bool Frustum::insideFrustum(const CollisionShape& b)
 {
-	if(m_frustumDirty)
-	{
-		// Force recalculation and tranform
-		resetTransform(m_trf);
-	}
+	update();
 
-	for(const Plane& plane : m_planes)
+	for(const Plane& plane : m_planesW)
 	{
 		if(b.testPlane(plane) < 0.0)
 		{
@@ -103,48 +74,79 @@ Bool Frustum::insideFrustum(const CollisionShape& b)
 //==============================================================================
 void Frustum::transform(const Transform& trf)
 {
-	const Transform* useTrf;
+	m_trf = m_trf.combineTransformations(trf);
+
 	if(m_frustumDirty)
 	{
-		m_frustumDirty = false;
-		recalculate();
-
-		useTrf = &m_trf;
+		// Update everything
+		updateInternal();
 	}
 	else
 	{
-		useTrf = &trf;
-	}
-
-	m_trf = m_trf.combineTransformations(trf);
+		// Update only the other shapes
+		recalculate(false, true);
 
-	// Transform the compound
-	CompoundShape::transform(*useTrf);
+		// Transform the compound
+		CompoundShape::transform(m_trf);
 
-	// Transform the planes
-	for(Plane& p : m_planes)
-	{
-		p.transform(*useTrf);
+		// Transform the planes
+		for(U i = 0; i < m_planes.getSize(); ++i)
+		{
+			m_planesW[i] = m_planes[i].getTransformed(m_trf);
+		}
 	}
 }
 
 //==============================================================================
 void Frustum::resetTransform(const Transform& trf)
 {
-	recalculate();
-	m_frustumDirty = false;
-	if(&m_trf != &trf)
+	m_trf = trf;
+
+	if(m_frustumDirty)
 	{
-		m_trf = trf;
+		// Update everything
+		updateInternal();
 	}
+	else
+	{
+		// Update only the other shapes
+		recalculate(false, true);
 	
+		// Transform the compound
+		CompoundShape::transform(m_trf);
+
+		// Transform the planes
+		for(U i = 0; i < m_planes.getSize(); ++i)
+		{
+			m_planesW[i] = m_planes[i].getTransformed(m_trf);
+		}
+	}
+}
+
+//==============================================================================
+void Frustum::update() const
+{
+	Frustum& self = *const_cast<Frustum*>(this);
+	if(self.m_frustumDirty)
+	{
+		self.updateInternal();
+	}
+}
+
+//==============================================================================
+void Frustum::updateInternal()
+{
+	ANKI_ASSERT(m_frustumDirty);
+	m_frustumDirty = false;	
+	recalculate(true, true);
+
 	// Transform the compound
 	CompoundShape::transform(m_trf);
 
 	// Transform the planes
-	for(Plane& p : m_planes)
+	for(U i = 0; i < m_planes.getSize(); ++i)
 	{
-		p.transform(m_trf);
+		m_planesW[i] = m_planes[i].getTransformed(m_trf);
 	}
 }
 
@@ -173,45 +175,47 @@ PerspectiveFrustum& PerspectiveFrustum::operator=(const PerspectiveFrustum& b)
 }
 
 //==============================================================================
-void PerspectiveFrustum::recalculate()
+void PerspectiveFrustum::recalculate(Bool planes, Bool other)
 {
-	// Planes
-	//
-	F32 c, s; // cos & sine
-
-	sinCos(getPi<F32>() + m_fovX / 2.0, s, c);
-	// right
-	m_planes[(U)PlaneType::RIGHT] = Plane(Vec4(c, 0.0, s, 0.0), 0.0);
-	// left
-	m_planes[(U)PlaneType::LEFT] = Plane(Vec4(-c, 0.0, s, 0.0), 0.0);
-
-	sinCos((getPi<F32>() + m_fovY) * 0.5, s, c);
-	// bottom
-	m_planes[(U)PlaneType::BOTTOM] = Plane(Vec4(0.0, s, c, 0.0), 0.0);
-	// top
-	m_planes[(U)PlaneType::TOP] = Plane(Vec4(0.0, -s, c, 0.0), 0.0);
-
-	// near
-	m_planes[(U)PlaneType::NEAR] = Plane(Vec4(0.0, 0.0, -1.0, 0.0), m_near);
-	// far
-	m_planes[(U)PlaneType::FAR] = Plane(Vec4(0.0, 0.0, 1.0, 0.0), -m_far);
-
-	// Rest
-	//
-	Vec4 eye = Vec4(0.0, 0.0, -m_near, 0.0);
-	for(LineSegment& ls : m_segments)
+	if(planes)
 	{
-		ls.setOrigin(eye);
+		F32 c, s; // cos & sine
+
+		sinCos(getPi<F32>() + m_fovX / 2.0, s, c);
+		// right
+		m_planes[(U)PlaneType::RIGHT] = Plane(Vec4(c, 0.0, s, 0.0), 0.0);
+		// left
+		m_planes[(U)PlaneType::LEFT] = Plane(Vec4(-c, 0.0, s, 0.0), 0.0);
+
+		sinCos((getPi<F32>() + m_fovY) * 0.5, s, c);
+		// bottom
+		m_planes[(U)PlaneType::BOTTOM] = Plane(Vec4(0.0, s, c, 0.0), 0.0);
+		// top
+		m_planes[(U)PlaneType::TOP] = Plane(Vec4(0.0, -s, c, 0.0), 0.0);
+
+		// near
+		m_planes[(U)PlaneType::NEAR] = Plane(Vec4(0.0, 0.0, -1.0, 0.0), m_near);
+		// far
+		m_planes[(U)PlaneType::FAR] = Plane(Vec4(0.0, 0.0, 1.0, 0.0), -m_far);
 	}
 
-	F32 x = m_far / tan((getPi<F32>() - m_fovX) / 2.0);
-	F32 y = tan(m_fovY / 2.0) * m_far;
-	F32 z = -m_far;
+	if(other)
+	{
+		Vec4 eye = Vec4(0.0, 0.0, -m_near, 0.0);
+		for(LineSegment& ls : m_segments)
+		{
+			ls.setOrigin(eye);
+		}
+
+		F32 x = m_far / tan((getPi<F32>() - m_fovX) / 2.0);
+		F32 y = tan(m_fovY / 2.0) * m_far;
+		F32 z = -m_far;
 
-	m_segments[0].setDirection(Vec4(x, y, z - m_near, 0.0)); // top right
-	m_segments[1].setDirection(Vec4(-x, y, z - m_near, 0.0)); // top left
-	m_segments[2].setDirection(Vec4(-x, -y, z - m_near, 0.0)); // bottom left
-	m_segments[3].setDirection(Vec4(x, -y, z - m_near, 0.0)); // bottom right
+		m_segments[0].setDirection(Vec4(x, y, z - m_near, 0.0)); // top right
+		m_segments[1].setDirection(Vec4(-x, y, z - m_near, 0.0)); // top left
+		m_segments[2].setDirection(Vec4(-x, -y, z - m_near, 0.0)); // bot left
+		m_segments[3].setDirection(Vec4(x, -y, z - m_near, 0.0)); // bot right
+	}
 }
 
 //==============================================================================
@@ -320,23 +324,36 @@ Mat4 OrthographicFrustum::calculateProjectionMatrix() const
 }
 
 //==============================================================================
-void OrthographicFrustum::recalculate()
+void OrthographicFrustum::recalculate(Bool planes, Bool other)
 {
-	// Planes
-	m_planes[(U)PlaneType::LEFT] = Plane(Vec4(1.0, 0.0, 0.0, 0.0), m_left);
-	m_planes[(U)PlaneType::RIGHT] = Plane(Vec4(-1.0, 0.0, 0.0, 0.0), -m_right);
-	m_planes[(U)PlaneType::NEAR] = Plane(Vec4(0.0, 0.0, -1.0, 0.0), m_near);
-	m_planes[(U)PlaneType::FAR] = Plane(Vec4(0.0, 0.0, 1.0, 0.0), -m_far);
-	m_planes[(U)PlaneType::TOP] = Plane(Vec4(0.0, -1.0, 0.0, 0.0), -m_top);
-	m_planes[(U)PlaneType::BOTTOM] = Plane(Vec4(0.0, 1.0, 0.0, 0.0), m_bottom);
-
-	// OBB
-	Vec4 c((m_right + m_left) * 0.5, 
-		(m_top + m_bottom) * 0.5, 
-		-(m_far + m_near) * 0.5,
-		0.0);
-	Vec4 e = Vec4(m_right, m_top, -m_far, 0.0) - c;
-	m_obb = Obb(c, Mat3x4::getIdentity(), e);
+	if(planes)
+	{
+		// Planes
+		m_planes[(U)PlaneType::LEFT] = 
+			Plane(Vec4(1.0, 0.0, 0.0, 0.0), m_left);
+		m_planes[(U)PlaneType::RIGHT] = 
+			Plane(Vec4(-1.0, 0.0, 0.0, 0.0), -m_right);
+
+		m_planes[(U)PlaneType::NEAR] = 
+			Plane(Vec4(0.0, 0.0, -1.0, 0.0), m_near);
+		m_planes[(U)PlaneType::FAR] = 
+			Plane(Vec4(0.0, 0.0, 1.0, 0.0), -m_far);
+		m_planes[(U)PlaneType::TOP] = 
+			Plane(Vec4(0.0, -1.0, 0.0, 0.0), -m_top);
+		m_planes[(U)PlaneType::BOTTOM] = 
+			Plane(Vec4(0.0, 1.0, 0.0, 0.0), m_bottom);
+	}
+
+	if(other)
+	{
+		// OBB
+		Vec4 c((m_right + m_left) * 0.5, 
+			(m_top + m_bottom) * 0.5, 
+			-(m_far + m_near) * 0.5,
+			0.0);
+		Vec4 e = Vec4(m_right, m_top, -m_far, 0.0) - c;
+		m_obb = Obb(c, Mat3x4::getIdentity(), e);
+	}
 }
 
 } // end namespace anki

+ 15 - 15
src/collision/Obb.cpp

@@ -11,25 +11,25 @@ namespace anki {
 
 //==============================================================================
 Obb::Obb()
-	:	Base(Type::OBB),
-		m_center(Vec4(0.0)),
-		m_rotation(Mat3x4::getIdentity()),
-		m_extend(Vec3(getEpsilon<F32>()), 0.0)
+:	Base(Type::OBB),
+	m_center(Vec4(0.0)),
+	m_rotation(Mat3x4::getIdentity()),
+	m_extend(Vec3(getEpsilon<F32>()), 0.0)
 {}
 
 //==============================================================================
 Obb::Obb(const Obb& b)
-	: 	Base(Type::OBB)
+: 	Base(Type::OBB)
 {
 	operator=(b);
 }
 
 //==============================================================================
 Obb::Obb(const Vec4& center, const Mat3x4& rotation, const Vec4& extend)
-	:	Base(Type::OBB), 
-		m_center(center),
-		m_rotation(rotation),
-		m_extend(extend)
+:	Base(Type::OBB), 
+	m_center(center),
+	m_rotation(rotation),
+	m_extend(extend)
 {}
 
 //==============================================================================
@@ -49,18 +49,18 @@ F32 Obb::testPlane(const Plane& p) const
 {
 	Mat3x4 rot = m_rotation;
 	rot.transposeRotationPart();
-	Vec3 xNormal = rot * p.getNormal();
+	Vec4 xNormal = (rot * p.getNormal()).xyz0();
 
 	// maximum extent in direction of plane normal
-	F32 r =
-		abs(m_extend.x() * xNormal.x()) +
-		abs(m_extend.y() * xNormal.y()) +
-		abs(m_extend.z() * xNormal.z());
+	Vec4 rv = m_extend * xNormal;
+	Vec4 rvabs = rv.getAbs();
+	F32 r = rvabs.x() + rvabs.y() + rvabs.z();
+
 	// signed distance between box center and plane
 	F32 d = p.test(m_center);
 
 	// return signed distance
-	if(fabs(d) < r)
+	if(abs(d) < r)
 	{
 		return 0.0;
 	}

+ 76 - 0
src/collision/Tests.cpp

@@ -4,4 +4,80 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/collision/Tests.h"
+#include "anki/collision/Aabb.h"
+#include "anki/collision/Sphere.h"
+#include "anki/collision/CompoundShape.h"
+#include "anki/collision/GjkEpa.h"
+#include "anki/util/Rtti.h"
+
+namespace anki {
+
+//==============================================================================
+// Misc                                                                        =
+//==============================================================================
+
+//==============================================================================
+static Bool gjk(const CollisionShape& a, const CollisionShape& b)
+{
+	Gjk gjk;
+	return gjk.intersect(
+		dcast<const ConvexShape&>(a), dcast<const ConvexShape&>(b));
+}
+
+//==============================================================================
+static Bool test(const Aabb& a, const Aabb& b)
+{
+	// if separated in x direction
+	if(a.getMin().x() > b.getMax().x() || b.getMin().x() > a.getMax().x())
+	{
+		return false;
+	}
+
+	// if separated in y direction
+	if(a.getMin().y() > b.getMax().y() || b.getMin().y() > a.getMax().y())
+	{
+		return false;
+	}
+
+	// if separated in z direction
+	if(a.getMin().z() > b.getMax().z() || b.getMin().z() > a.getMax().z())
+	{
+		return false;
+	}
+
+	// no separation, must be intersecting
+	return true;
+}
+
+//==============================================================================
+static Bool test(const Sphere& a, const Sphere& b)
+{
+	F32 tmp = a.getRadius() + b.getRadius();
+	return (a.getCenter() - b.getCenter()).getLengthSquared() <= tmp * tmp;
+}
+
+//==============================================================================
+// Matrix                                                                      =
+//==============================================================================
+
+template<typename A, typename B>
+Bool t(const CollisionShape& a, const CollisionShape& b)
+{
+	return test(dcast<const A&>(a), dcast<const B&>(b));
+}
+
+using Callback = Bool (*)(const CollisionShape& a, const CollisionShape& b);
+
+static const U COUNT = U(CollisionShape::Type::COUNT);
+
+static const Callback matrix[COUNT][COUNT] = {
+	// AABB         Comp     LS       OBB      PL       S
+	{t<Aabb, Aabb>, nullptr, nullptr, gjk,     nullptr, nullptr          },  // AABB
+	{nullptr,       nullptr, nullptr, nullptr, nullptr, nullptr          },  // Comp
+	{nullptr,       nullptr, nullptr, nullptr, nullptr, nullptr          },  // LS
+	{gjk,           nullptr, nullptr, gjk,     nullptr, nullptr          },  // OBB
+	{nullptr,       nullptr, nullptr, nullptr, nullptr, nullptr          },  // PL
+	{nullptr,       nullptr, nullptr, gjk,     nullptr, t<Sphere, Sphere>}}; // S
+
+} // end namespace anki
 

+ 1 - 1
src/core/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Timestamp.cpp Counters.cpp Config.cpp)
+set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Counters.cpp Config.cpp)
 
 if(${ANKI_WINDOW_BACKEND} STREQUAL "GLXX11")
 	set(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowGlxX11.cpp)

+ 12 - 10
testapp/Main.cpp

@@ -41,6 +41,8 @@ App* app;
 ModelNode* horse;
 PerspectiveCamera* cam;
 
+#define NO_PLAYER 1
+
 
 //==============================================================================
 Error init()
@@ -225,7 +227,7 @@ Error init()
 #if 1
 	// horse
 	err = scene.newSceneNode<ModelNode>("horse", horse, 
-		"models/crate0/crate0.ankimdl");
+		"models/horse/horse.ankimdl");
 	if(err) return err;
 	//horse->getComponent<MoveComponent>().setLocalTransform(
 	//	Transform(Vec4(-2, 0, 0, 0.0), Mat3x4::getIdentity(), 0.7));
@@ -238,21 +240,21 @@ Error init()
 	}
 #endif
 
-	if(0)
+	if(1)
 	{
 		err = scene.newSceneNode<PointLight>("plight0", point);
 		if(err) return err;
 
 		lightc = point->tryGetComponent<LightComponent>();
-		lightc->setRadius(0.01);
-		lightc->setDiffuseColor(Vec4(0.6));
+		lightc->setRadius(6.01);
+		lightc->setDiffuseColor(Vec4(1.0));
 		lightc->setSpecularColor(Vec4(0.6, 0.6, 0.3, 1.0));
 
 		move = point->tryGetComponent<MoveComponent>();
-		move->setLocalOrigin(Vec4(0.0, 1.4, 0.6, 0.0));
+		move->setLocalOrigin(Vec4(2.0, 1.4, 0.6, 0.0));
 	}
 
-#if 1
+#if 0
 	{
 		ScriptResourcePointer script;
 
@@ -264,7 +266,7 @@ Error init()
 	}
 #endif
 
-#if 1
+#if !NO_PLAYER
 	PlayerNode* pnode;
 	scene.newSceneNode<PlayerNode>("player", pnode, Vec4(1.0, 3.0, 0.0, 0.0));
 
@@ -420,7 +422,7 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 		renderer.takeScreenshot("screenshot.tga");
 	}
 
-#if 0
+#if NO_PLAYER
 	if(in.getKey(KeyCode::UP)) mover->rotateLocalX(ang);
 	if(in.getKey(KeyCode::DOWN)) mover->rotateLocalX(-ang);
 	if(in.getKey(KeyCode::LEFT)) mover->rotateLocalY(ang);
@@ -457,7 +459,7 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 	}
 #endif
 
-#if 0
+#if NO_PLAYER
 	if(in.getMousePosition() != Vec2(0.0))
 	{
 		F32 angY = -ang * in.getMousePosition().x() * mouseSensivity *
@@ -523,7 +525,7 @@ Error initSubsystems(int argc, char* argv[])
 
 	//config.set("maxTextureSize", 256);
 
-	config.set("fullscreenDesktopResolution", true);
+	config.set("fullscreenDesktopResolution", false);
 	config.set("debugContext", false);
 
 	app = new App;