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

Merge branch 'master' of https://github.com/taylor001/crown

Dexter89 пре 12 година
родитељ
комит
a02b000451

+ 0 - 1
engine/CMakeLists.txt

@@ -126,7 +126,6 @@ set (CONTAINERS_HEADERS
 	core/containers/Map.h
 	core/containers/PriorityQueue.h
 	core/containers/Queue.h
-	core/containers/RBTree.h
 	core/containers/Vector.h
 )
 

+ 2 - 8
engine/ConsoleServer.cpp

@@ -40,15 +40,9 @@ namespace crown
 {
 
 //-----------------------------------------------------------------------------
-ConsoleServer::ConsoleServer(uint16_t port)
-	: m_port(port)
+void ConsoleServer::init(uint16_t port, bool wait)
 {
-}
-
-//-----------------------------------------------------------------------------
-void ConsoleServer::init(bool wait)
-{
-	m_server.open(m_port);
+	m_server.open(port);
 	m_server.listen(5);
 
 	if (wait)

+ 2 - 6
engine/ConsoleServer.h

@@ -53,12 +53,9 @@ class ConsoleServer
 {
 public:
 
-	/// Listens on the given @a port.
-								ConsoleServer(uint16_t port);
-
-	/// Initializes the system. If @a wait is true, this function
+	/// Listens on the given @a port. If @a wait is true, this function
 	/// blocks until a client is connected.
-	void						init(bool wait);
+	void						init(uint16_t port, bool wait);
 	void						shutdown();
 
 	void						log_to_all(const char* message, LogSeverity::Enum severity);
@@ -83,7 +80,6 @@ private:
 
 private:
 
-	uint16_t					m_port;
 	TCPServer					m_server;
 	ClientArray					m_clients;
 };

+ 7 - 7
engine/Crown.h

@@ -50,15 +50,15 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector4.h"
 
 // Core/Containers
-#include "Map.h"
-#include "RBTree.h"
 #include "ContainerTypes.h"
-#include "Vector.h"
-#include "Queue.h"
-#include "PriorityQueue.h"
-#include "IdTable.h"
-#include "IdArray.h"
 #include "EventStream.h"
+#include "Hash.h"
+#include "IdArray.h"
+#include "IdTable.h"
+#include "Map.h"
+#include "PriorityQueue.h"
+#include "Queue.h"
+#include "Vector.h"
 
 // Core/Strings
 #include "StringUtils.h"

+ 2 - 2
engine/Device.cpp

@@ -121,8 +121,8 @@ void Device::init()
 
 	// RPC only in debug or development builds
 	#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
-		m_console = CE_NEW(m_allocator, ConsoleServer)(m_console_port);
-		m_console->init(false);
+		m_console = CE_NEW(m_allocator, ConsoleServer)();
+		m_console->init(m_console_port, false);
 	#endif
 
 	Log::d("Creating filesystem...");

+ 24 - 0
engine/core/containers/ContainerTypes.h

@@ -136,4 +136,28 @@ struct Hash
 	Array<Entry> _data;
 };
 
+/// Map from key to value. Uses a Vector internally, so, definitely
+/// not suited to performance-critical stuff.
+///
+/// @ingroup Containers
+template <typename TKey, typename TValue>
+struct Map
+{
+	Map(Allocator& a);
+
+	struct Node
+	{
+		TKey key;
+		TValue value;
+		uint32_t left;
+		uint32_t right;
+		uint32_t parent;
+		uint32_t color;
+	};
+
+	uint32_t m_root;
+	uint32_t m_sentinel;
+	Vector<Node> m_data;
+};
+
 } // namespace crown

+ 716 - 14
engine/core/containers/Map.h

@@ -26,29 +26,731 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "Types.h"
-#include "RBTree.h"
+#include "ContainerTypes.h"
+#include "Vector.h"
+
+// #define RBTREE_VERIFY
 
 namespace crown
 {
 
-class Allocator;
+/// Functions to manipulate Map
+///
+/// @ingroup Containers
+namespace map
+{
+	/// Returns the number of items in the map @a m.
+	template <typename TKey, typename TValue> uint32_t size(const Map<TKey, TValue>& m);
+
+	/// Returns whether the given @a key exists in the map @a m.
+	template <typename TKey, typename TValue> bool has(const Map<TKey, TValue>& m, const TKey key);
+
+	/// Returns the value for the given @a key or @a deffault if
+	/// the key does not exist in the map.
+	template <typename TKey, typename TValue> const TValue& get(const Map<TKey, TValue>& m, const TKey key, const TValue& deffault);
+
+	/// Sets the @a value for the @a key in the map.
+	template <typename TKey, typename TValue> void set(Map<TKey, TValue>& m, const TKey& key, const TValue& value);
+
+	/// Removes the @a key from the map if it exists.
+	template <typename TKey, typename TValue> void remove(Map<TKey, TValue>& m, const TKey& key);
 
-//Note: TKey must implement operators < and ==
-template<class TKey, class TValue>
-class Map : public RBTree<TKey, TValue>
+	/// Removes all the items in the map.
+	/// @note Calls destructor on the items.
+	template <typename TKey, typename TValue> void clear(Map<TKey, TValue>& m);
+
+	/// Returns a pointer to the first item in the map, can be used to
+	/// efficiently iterate over the elements (in random order).
+	template <typename TKey, typename TValue> const typename Map<TKey, TValue>::Node* begin(const Map<TKey, TValue>& m);
+	template <typename TKey, typename TValue> const typename Map<TKey, TValue>::Node* end(const Map<TKey, TValue>& m);
+} // namespace map
+
+namespace map_internal
 {
-public:
-	Map(Allocator& allocator) : RBTree<TKey, TValue>(allocator) {};
-	~Map() {};
+	const uint32_t BLACK = 0xB1B1B1B1u;
+	const uint32_t RED = 0xEDEDEDEDu;
+	const uint32_t NIL = 0xFFFFFFFFu;
 
-	//using RBTree<TKey, TValue>::Pair;
+	template <typename TKey, typename TValue>
+	inline uint32_t root(const Map<TKey, TValue>& m)
+	{
+		return m.m_root;
+	}
 
-	TValue& operator[](const TKey& key)
+	template <typename TKey, typename TValue>
+	inline uint32_t parent(const Map<TKey, TValue>& m, uint32_t n)
 	{
-		RBTreeNode<TKey, TValue>* n = RBTree<TKey, TValue>::find_or_add(key);
-		return n->item.value;
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+		return m.m_data[n].parent;
 	}
-};
+	
+	template <typename TKey, typename TValue>
+	inline uint32_t left(const Map<TKey, TValue>& m, uint32_t n)
+	{
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+		return m.m_data[n].left;
+	}
+	
+	template <typename TKey, typename TValue>
+	inline uint32_t right(const Map<TKey, TValue>& m, uint32_t n)
+	{
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+		return m.m_data[n].right;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t color(const Map<TKey, TValue>& m, uint32_t n)
+	{
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+		return m.m_data[n].color;
+	}
+
+	#ifdef RBTREE_VERIFY
+	template<typename TKey, typename TValue>
+	inline int32_t dbg_verify(Map<TKey, TValue>& m, uint32_t n)
+	{
+		if (n == m.m_sentinel)
+		{
+			return 0;
+		}
+
+		if (left(m, n) != m.m_sentinel)
+		{
+			CE_ASSERT(parent(m, left(m, n)) == n, "Bad RBTree");
+			CE_ASSERT(m.m_data[left(m, n)].key < m.m_data[n].key, "Bad RBTree");
+		}
+
+		if (right(m, n) != m.m_sentinel)
+		{
+			CE_ASSERT(parent(m, right(m, n)) == n, "Bad RBTree");
+			CE_ASSERT(m.m_data[n].key < m.m_data[right(m, n)].key, "Bad RBTree");
+		}
+
+		int32_t bhL = dbg_verify(m, left(m, n));
+		int32_t bhR = dbg_verify(m, right(m, n));
+		CE_ASSERT(bhL == bhR, "Bad RBTree");
+
+		if (color(m, n) == BLACK)
+		{
+			bhL += 1;
+		}
+		else
+		{
+			if (parent(m, n) != NIL && color(m, parent(m, n)) == RED)
+			{
+				CE_ASSERT(false, "Bad RBTree");
+			}
+		}
+
+		return bhL;
+	}
+
+	template<typename TKey, typename TValue>
+	inline int32_t dump(Map<TKey, TValue>& m)
+	{
+		for (uint32_t i = 0; i < vector::size(m.m_data); i++)
+		{
+			printf("%d = [%d, %d, %d] ", i, parent(m, i), left(m, i), right(m, i));
+		}
+		printf("\n");
+		return 0;
+	}
+	#endif
+
+	template <typename TKey, typename TValue>
+	inline uint32_t min(const Map<TKey, TValue>& m, uint32_t x)
+	{
+		if (x == m.m_sentinel)
+		{
+			return x;
+		}
+
+		while (left(m, x) != m.m_sentinel)
+		{
+			x = left(m, x);
+		}
+
+		return x;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t max(const Map<TKey, TValue>& m, uint32_t x)
+	{
+		if (x == m.m_sentinel)
+		{
+			return x;
+		}
+
+		while (right(m, x) != m.m_sentinel)
+		{
+			x = right(m, x);
+		}
+
+		return x;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t successor(const Map<TKey, TValue>& m, uint32_t x)
+	{
+		if (right(m, x) != m.m_sentinel)
+		{
+			return min(m, right(m, x));
+		}
+
+		uint32_t y = parent(m, x);
+
+		while (y != NIL && x == right(m, y))
+		{
+			x = y;
+			y = parent(m, y);
+		}
+
+		return y;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t predecessor(const Map<TKey, TValue>& m, uint32_t x)
+	{
+		if (left(m, x) != m.m_sentinel)
+		{
+			return max(m, left(m, x));
+		}
+
+		uint32_t y = parent(m, x);
+
+		while (y != NIL && x == left(m, y))
+		{
+			x = y;
+			y = parent(m, y);
+		}
+
+		return y;
+	}
+
+	template <typename TKey, typename TValue>
+	inline void rotate_left(Map<TKey, TValue>& m, uint32_t x)
+	{
+		CE_ASSERT(x < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), x);
+
+		uint32_t y = right(m, x);
+		m.m_data[x].right = left(m, y);
+
+		if (left(m, y) != m.m_sentinel)
+		{
+			m.m_data[left(m, y)].parent = x;
+		}
+
+		m.m_data[y].parent = parent(m, x);
+
+		if (parent(m, x) == NIL)
+		{
+			m.m_root = y;
+		}
+		else
+		{
+			if (x == left(m, parent(m, x)))
+			{
+				m.m_data[parent(m, x)].left = y;
+			}
+			else
+			{
+				m.m_data[parent(m, x)].right = y;
+			}
+		}
+
+		m.m_data[y].left = x;
+		m.m_data[x].parent = y;
+	}
+
+	template <typename TKey, typename TValue>
+	inline void rotate_right(Map<TKey, TValue>& m, uint32_t x)
+	{
+		CE_ASSERT(x < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), x);
+
+		uint32_t y = left(m, x);
+		m.m_data[x].left = right(m, y);
+
+		if (right(m, y) != m.m_sentinel)
+		{
+			m.m_data[right(m, y)].parent = x;
+		}
+
+		m.m_data[y].parent = parent(m, x);
+
+		if (parent(m, x) == NIL)
+		{
+			m.m_root = y;
+		}
+		else
+		{
+			if (x == left(m, parent(m, x)))
+			{
+				m.m_data[parent(m, x)].left = y;
+			}
+			else
+			{
+				m.m_data[parent(m, x)].right = y;
+			}
+		}
+
+		m.m_data[y].right = x;
+		m.m_data[x].parent = y;
+	}
+
+	template <typename TKey, typename TValue>
+	inline void destroy(Map<TKey, TValue>& m, uint32_t n)
+	{
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+
+		uint32_t x = vector::size(m.m_data) - 1;
+
+		if (x == m.m_root)
+		{
+			m.m_root = n;
+
+			if (left(m, x) != NIL)
+				m.m_data[left(m, x)].parent = n;
+			if (right(m, x) != NIL)
+				m.m_data[right(m, x)].parent = n;
+
+			m.m_data[n] = m.m_data[x];
+		}
+		else
+		{
+			if (x != n)
+			{
+				if (x == left(m, parent(m, x)))
+				{
+					m.m_data[parent(m, x)].left = n;
+				}
+				else if (x == right(m, parent(m, x)))
+				{
+					m.m_data[parent(m, x)].right = n;
+				}
+
+				if (left(m, x) != NIL)
+					m.m_data[left(m, x)].parent = n;
+				if (right(m, x) != NIL)
+					m.m_data[right(m, x)].parent = n;
+
+				m.m_data[n] = m.m_data[x];
+			}
+		}
+
+		#ifdef RBTREE_VERIFY
+			dbg_verify(m, m.m_root);
+		#endif
+
+		vector::pop_back(m.m_data);
+	}
+
+	template <typename TKey, typename TValue>
+	inline void insert_fixup(Map<TKey, TValue>& m, uint32_t n)
+	{
+		CE_ASSERT(n < vector::size(m.m_data), "Index out of bounds (size = %d, n = %d)", vector::size(m.m_data), n);
+
+		uint32_t x;
+		uint32_t y;
+
+		while (n != root(m) && color(m, parent(m, n)) == RED)
+		{
+			x = parent(m, n);
+
+			if (x == left(m, parent(m, x)))
+			{
+				y = right(m, parent(m, x));
+
+				if (color(m, y) == RED)
+				{
+					m.m_data[x].color = BLACK;
+					m.m_data[y].color = BLACK;
+					m.m_data[parent(m, x)].color = RED;
+					n = parent(m, x);
+					continue;
+				}
+				else
+				{
+					if (n == right(m, x))
+					{
+						n = x;
+						rotate_left(m, n);
+						x = parent(m, n);
+					}
+
+					m.m_data[x].color = BLACK;
+					m.m_data[parent(m, x)].color = RED;
+					rotate_right(m, parent(m, x));
+				}
+			}
+			else
+			{
+				y = left(m, parent(m, x));
+
+				if (color(m, y) == RED)
+				{
+					m.m_data[x].color = BLACK;
+					m.m_data[y].color = BLACK;
+					m.m_data[parent(m, x)].color = RED;
+					n = parent(m, x);
+					continue;
+				}
+				else
+				{
+					if (n == left(m, x))
+					{
+						n = x;
+						rotate_right(m, n);
+						x = parent(m, n);
+					}
+
+					m.m_data[x].color = BLACK;
+					m.m_data[parent(m, x)].color = RED;
+					rotate_left(m, parent(m, x));
+				}
+			}
+		}
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t inner_find(const Map<TKey, TValue>& m, const TKey key)
+	{
+		uint32_t x = m.m_root;
+
+		while (x != m.m_sentinel)
+		{
+			if (m.m_data[x].key < key)
+			{
+				if (right(m, x) == m.m_sentinel)
+				{
+					return x;
+				}
+
+				x = right(m, x);
+			}
+			else if (key < m.m_data[x].key)
+			{
+				if (left(m, x) == m.m_sentinel)
+				{
+					return x;
+				}
+
+				x = left(m, x);
+			}
+			else
+			{
+				break;
+			}
+		}
+
+		return x;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t find_or_fail(const Map<TKey, TValue>& m, const TKey key)
+	{
+		uint32_t p = inner_find(m, key);
+
+		if (p != m.m_sentinel && m.m_data[p].key == key)
+			return p;
+
+		return NIL;
+	}
+
+	template <typename TKey, typename TValue>
+	inline uint32_t find_or_add(Map<TKey, TValue>& m, const TKey key)
+	{
+		uint32_t p = inner_find(m, key);
+
+		if (p != m.m_sentinel && m.m_data[p].key == key)
+		{
+			return p;
+		}
+
+		typename Map<TKey, TValue>::Node n;
+		n.key = key;
+		n.value = TValue();
+		n.color = RED;
+		n.left = m.m_sentinel;
+		n.right = m.m_sentinel;
+		n.parent = NIL;
+
+		if (p == m.m_sentinel)
+		{
+			m.m_root = n;
+		}
+		else
+		{
+			if (key < m.m_data[p].key)
+			{
+				m.m_data[p].left = n;
+			}
+			else
+			{
+				m.m_data[p].right = n;
+			}
+
+			m.m_data[n].parent = p;
+		}
+
+		add_fixup(m, n);
+		m.m_data[m.m_root].color = BLACK;
+		#ifdef RBTREE_VERIFY
+			dbg_verify(m, m.m_root);
+		#endif
+		return n;
+	}
+} // namespace map_internal
+
+namespace map
+{
+	template <typename TKey, typename TValue>
+	uint32_t size(const Map<TKey, TValue>& m)
+	{
+		CE_ASSERT(vector::size(m.m_data) > 0, "Bad Map"); // There should be at least sentinel
+		return vector::size(m.m_data) - 1;
+	}
+
+	template <typename TKey, typename TValue>
+	inline bool has(const Map<TKey, TValue>& m, const TKey key)
+	{
+		return map_internal::find_or_fail(m, key) != map_internal::NIL;
+	}
+
+	template <typename TKey, typename TValue>
+	inline const TValue& get(const Map<TKey, TValue>& m, const TKey key, const TValue& deffault)
+	{
+		uint32_t p = map_internal::inner_find(m, key);
+
+		if (p != m.m_sentinel && m.m_data[p].key == key)
+		{
+			return m.m_data[p].value;
+		}
+
+		return deffault;
+	}
+
+	template <typename TKey, typename TValue>
+	inline void set(Map<TKey, TValue>& m, const TKey& key, const TValue& value)
+	{
+		typename Map<TKey, TValue>::Node node;
+		node.key = key;
+		node.value = value;
+		node.color = map_internal::RED;
+		node.left = m.m_sentinel;
+		node.right = m.m_sentinel;
+		node.parent = map_internal::NIL;
+		uint32_t n = vector::push_back(m.m_data, node);
+		uint32_t x = m.m_root;
+		uint32_t y = map_internal::NIL;
+
+		if (x == m.m_sentinel)
+			m.m_root = n;
+		else
+		{
+			while (x != m.m_sentinel)
+			{
+				y = x;
+
+				if (key < m.m_data[x].key)
+					x = m.m_data[x].left;
+				else
+					x = m.m_data[x].right;
+			}
+
+			if (key < m.m_data[y].key)
+				m.m_data[y].left = n;
+			else
+				m.m_data[y].right = n;
+
+			m.m_data[n].parent = y;
+		}
+
+		map_internal::insert_fixup(m, n);
+		m.m_data[m.m_root].color = map_internal::BLACK;
+		#ifdef RBTREE_VERIFY
+			map_internal::dbg_verify(m, m.m_root);
+		#endif
+	}
+
+	template <typename TKey, typename TValue>
+	inline void remove(Map<TKey, TValue>& m, const TKey& key)
+	{
+		using namespace map_internal;
+
+		uint32_t n = inner_find(m, key);
+
+		if (!(m.m_data[n].key == key))
+		{
+			return;
+		}
+
+		uint32_t x;
+		uint32_t y;
+
+		if (left(m, n) == m.m_sentinel || right(m, n) == m.m_sentinel)
+		{
+			y = n;
+		}
+		else
+		{
+			y = successor(m, n);
+		}
+
+		if (left(m, y) != m.m_sentinel)
+		{
+			x = left(m, y);
+		}
+		else
+		{
+			x = right(m, y);
+		}
+
+		m.m_data[x].parent = parent(m, y);
+
+		if (parent(m, y) != map_internal::NIL)
+		{
+			if (y == left(m, parent(m, y)))
+			{
+				m.m_data[parent(m, y)].left = x;
+			}
+			else
+			{
+				m.m_data[parent(m, y)].right = x;
+			}
+		}
+		else
+		{
+			m.m_root = x;
+		}
+
+		if (y != n)
+		{
+			m.m_data[n].key = m.m_data[y].key;
+			m.m_data[n].value = m.m_data[y].value;
+		}
+
+		// Do the fixup
+		if (color(m, y) == map_internal::BLACK)
+		{
+			uint32_t y;
+
+			while (x != m.m_root && color(m, x) == map_internal::BLACK)
+			{
+				if (x == left(m, parent(m, x)))
+				{
+					y = right(m, parent(m, x));
+
+					if (color(m, y) == map_internal::RED)
+					{
+						m.m_data[y].color = map_internal::BLACK;
+						m.m_data[parent(m, x)].color = map_internal::RED;
+						rotate_left(m, parent(m, x));
+						y = right(m, parent(m, x));
+					}
+
+					if (color(m, left(m, y)) == map_internal::BLACK && color(m, right(m, y)) == map_internal::BLACK)
+					{
+						m.m_data[y].color = map_internal::RED;
+						x = parent(m, x);
+					}
+					else
+					{
+						if (color(m, right(m, y)) == map_internal::BLACK)
+						{
+							m.m_data[left(m, y)].color = map_internal::BLACK;
+							m.m_data[y].color = map_internal::RED;
+							rotate_right(m, y);
+							y = right(m, parent(m, x));
+						}
+
+						m.m_data[y].color = color(m, parent(m, x));
+						m.m_data[parent(m, x)].color = map_internal::BLACK;
+						m.m_data[right(m, y)].color = map_internal::BLACK;
+						rotate_left(m, parent(m, x));
+						x = m.m_root;
+					}
+				}
+				else
+				{
+					y = left(m, parent(m, x));
+
+					if (color(m, y) == map_internal::RED)
+					{
+						m.m_data[y].color = map_internal::BLACK;
+						m.m_data[parent(m, x)].color = map_internal::RED;
+						rotate_right(m, parent(m, x));
+						y = left(m, parent(m, x));
+					}
+
+					if (color(m, right(m, y)) == map_internal::BLACK && color(m, left(m, y)) == map_internal::BLACK)
+					{
+						m.m_data[y].color = map_internal::RED;
+						x = parent(m, x);
+					}
+					else
+					{
+						if (color(m, left(m, y)) == map_internal::BLACK)
+						{
+							m.m_data[right(m, y)].color = map_internal::BLACK;
+							m.m_data[y].color = map_internal::RED;
+							rotate_left(m, y);
+							y = left(m, parent(m, x));
+						}
+
+						m.m_data[y].color = color(m, parent(m, x));
+						m.m_data[parent(m, x)].color = map_internal::BLACK;
+						m.m_data[left(m, y)].color = map_internal::BLACK;
+						rotate_right(m, parent(m, x));
+						x = m.m_root;
+					}
+				}
+			}
+
+			m.m_data[x].color = map_internal::BLACK;
+		}
+
+		destroy(m, y);
+	 	#ifdef RBTREE_VERIFY
+			map_internal::dbg_verify(m, m.m_root);
+	 	#endif
+	}
+
+	template <typename TKey, typename TValue>
+	void clear(Map<TKey, TValue>& m)
+	{
+		vector::clear(m.m_data);
+
+		m.m_root = 0;
+		m.m_sentinel = 0;
+
+		typename Map<TKey, TValue>::Node r;
+		r.key = TKey();
+		r.value = TValue();
+		r.left = map_internal::NIL;
+		r.right = map_internal::NIL;
+		r.parent = map_internal::NIL;
+		r.color = map_internal::BLACK;
+		vector::push_back(m.m_data, r);
+	}
+
+	template <typename TKey, typename TValue>
+	const typename Map<TKey, TValue>::Node* begin(const Map<TKey, TValue>& m)
+	{
+		return vector::begin(m.m_data) + 1; // Skip sentinel at index 0
+	}
+
+	template <typename TKey, typename TValue>
+	const typename Map<TKey, TValue>::Node* end(const Map<TKey, TValue>& m)
+	{
+		return vector::end(m.m_data);
+	}
+} // namespace map
+
+template <typename TKey, typename TValue>
+inline Map<TKey, TValue>::Map(Allocator& a)
+	: m_data(a)
+{
+	map::clear(*this);
+}
 
 } // namespace crown

+ 0 - 696
engine/core/containers/RBTree.h

@@ -1,696 +0,0 @@
-/*
-Copyright (c) 2013 Daniele Bartolini, Michele Rossi
-Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#pragma once
-
-#include <cstdlib>
-
-#include "Assert.h"
-#include "Types.h"
-#include "Allocator.h"
-
-namespace crown
-{
-
-enum RBTreeNodeColor { RED, BLACK };
-
-template<typename TKey, typename TValue>
-struct RBTreePair
-{
-public:
-	RBTreePair(const TKey& k, const TValue& v):
-		key(k), value(v)
-	{ }
-
-	RBTreePair(const RBTreePair& p):
-		key(p.key), value(p.value)
-	{ }
-
-	TKey key;
-	TValue value;
-};
-
-template<typename TKey, typename TValue>
-struct RBTreeNode
-{
-	RBTreeNode(const TKey& key, const TValue& value):
-		item(key, value)
-	{
-		left = NULL;
-		right = NULL;
-		parent = NULL;
-		color = BLACK;
-	}
-
-	RBTreePair<TKey, TValue> item;
-	struct RBTreeNode<TKey, TValue>* left;
-	struct RBTreeNode<TKey, TValue>* right;
-	struct RBTreeNode<TKey, TValue>* parent;
-	enum RBTreeNodeColor color;
-};
-
-template<typename TKey, typename TValue>
-class RBTree
-{
-protected:
-	typedef RBTreeNode<TKey, TValue> Node;
-	typedef RBTreePair<TKey, TValue> Pair;
-
-public:
-	RBTree(Allocator& allocator);
-	~RBTree();
-
-	Pair& add(const TKey& key, const TValue& value);
-	void remove(const TKey& key);
-	bool contains(const TKey& key) const;
-	void clear();
-
-	inline int32_t size() const
-	{
-		return m_size;
-	}
-
-protected:
-
-	Node* find_or_add(TKey key);
-
-private:
-
-	Allocator&		m_allocator;
-
-	Node* m_root;
-	Node* m_sentinel;
-	int32_t m_size;
-
-	Node* predecessor(Node* n) const;
-	Node* successor(Node* n) const;
-	Node* min(Node* n) const;
-	Node* max(Node* n) const;
-	inline void rotate_left(Node* n);
-	inline void rotate_right(Node* n);
-
-	Node* inner_find(TKey key) const;
-	void add_fixup(Node* n);
-	void inner_clear(Node* n);
-
-#ifdef RBTREE_VERIFY
-	int32_t dbg_verify(Node* n) const;
-#endif
-};
-
-template<typename TKey, typename TValue>
-RBTree<TKey, TValue>::RBTree(Allocator& allocator) : m_allocator(allocator)
-{
-	m_sentinel = CE_NEW(m_allocator, Node)(TKey(), TValue());
-	m_root = m_sentinel;
-	m_size = 0;
-}
-
-template<typename TKey, typename TValue>
-RBTree<TKey, TValue>::~RBTree()
-{
-	clear();
-	CE_DELETE(m_allocator, m_sentinel);
-}
-
-template<typename TKey, typename TValue>
-RBTreePair<TKey, TValue>& RBTree<TKey, TValue>::add(const TKey& key, const TValue& value)
-{
-	Node* n = CE_NEW(m_allocator, Node)(key, value);
-	n->color = RED;
-	n->left = m_sentinel;
-	n->right = m_sentinel;
-	Pair& pair = n->item;
-	Node* x = m_root;
-	Node* y = NULL;
-
-	if (x == m_sentinel)
-	{
-		m_root = n;
-	}
-	else
-	{
-		while (x != m_sentinel)
-		{
-			y = x;
-
-			if (key < x->item.key)
-			{
-				x = x->left;
-			}
-			else
-			{
-				x = x->right;
-			}
-		}
-
-		if (key < y->item.key)
-		{
-			y->left = n;
-		}
-		else
-		{
-			y->right = n;
-		}
-
-		n->parent = y;
-	}
-
-	add_fixup(n);
-	m_root->color = BLACK;
-	m_size++;
-#ifdef RBTREE_VERIFY
-	dbg_verify(m_root);
-#endif
-	return pair;
-}
-
-template<typename TKey, typename TValue>
-void RBTree<TKey, TValue>::remove(const TKey& key)
-{
-	Node* n = inner_find(key);
-
-	if (!(n->item.key == key))
-	{
-		return;
-	}
-
-	Node* x;
-	Node* y;
-
-	if (n->left == m_sentinel || n->right == m_sentinel)
-	{
-		y = n;
-	}
-	else
-	{
-		y = successor(n);
-	}
-
-	if (y->left != m_sentinel)
-	{
-		x = y->left;
-	}
-	else
-	{
-		x = y->right;
-	}
-
-	x->parent = y->parent;
-
-	if (y->parent != NULL)
-	{
-		if (y == y->parent->left)
-		{
-			y->parent->left = x;
-		}
-		else
-		{
-			y->parent->right = x;
-		}
-	}
-	else
-	{
-		m_root = x;
-	}
-
-	if (y != n)
-	{
-		n->item = y->item;
-	}
-
-	//Do the fixup
-	if (y->color == BLACK)
-	{
-		Node* y;
-
-		while (x != m_root && x->color == BLACK)
-		{
-			if (x == x->parent->left)
-			{
-				y = x->parent->right;
-
-				if (y->color == RED)
-				{
-					y->color = BLACK;
-					x->parent->color = RED;
-					rotate_left(x->parent);
-					y = x->parent->right;
-				}
-
-				if (y->left->color == BLACK && y->right->color == BLACK)
-				{
-					y->color = RED;
-					x = x->parent;
-				}
-				else
-				{
-					if (y->right->color == BLACK)
-					{
-						y->left->color = BLACK;
-						y->color = RED;
-						rotate_right(y);
-						y = x->parent->right;
-					}
-
-					y->color = x->parent->color;
-					x->parent->color = BLACK;
-					y->right->color = BLACK;
-					rotate_left(x->parent);
-					x = m_root;
-				}
-			}
-			else
-			{
-				y = x->parent->left;
-
-				if (y->color == RED)
-				{
-					y->color = BLACK;
-					x->parent->color = RED;
-					rotate_right(x->parent);
-					y = x->parent->left;
-				}
-
-				if (y->right->color == BLACK && y->left->color == BLACK)
-				{
-					y->color = RED;
-					x = x->parent;
-				}
-				else
-				{
-					if (y->left->color == BLACK)
-					{
-						y->right->color = BLACK;
-						y->color = RED;
-						rotate_left(y);
-						y = x->parent->left;
-					}
-
-					y->color = x->parent->color;
-					x->parent->color = BLACK;
-					y->left->color = BLACK;
-					rotate_right(x->parent);
-					x = m_root;
-				}
-			}
-		}
-
-		x->color = BLACK;
-	}
-
-	CE_DELETE(m_allocator, y);
-	m_size -= 1;
-#ifdef RBTREE_VERIFY
-	dbg_verify(m_root);
-#endif
-}
-
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::find_or_add(TKey key)
-{
-	Node* p = inner_find(key);
-
-	if (p != m_sentinel && p->item.key == key)
-	{
-		return p;
-	}
-
-	Node* n = CE_NEW(m_allocator, Node)(key, TValue());
-	n->color = RED;
-	n->left = m_sentinel;
-	n->right = m_sentinel;
-
-	if (p == m_sentinel)
-	{
-		m_root = n;
-	}
-	else
-	{
-		if (key < p->item.key)
-		{
-			p->left = n;
-		}
-		else
-		{
-			p->right = n;
-		}
-
-		n->parent = p;
-	}
-
-	add_fixup(n);
-	m_root->color = BLACK;
-	m_size++;
-#ifdef RBTREE_VERIFY
-	dbg_verify(m_root);
-#endif
-	return n;
-}
-
-template<typename TKey, typename TValue>
-void RBTree<TKey, TValue>::clear()
-{
-	Node* tmp = m_root;
-	m_root = m_sentinel;
-	inner_clear(tmp);
-
-	m_size = 0;
-}
-
-template<typename TKey, typename TValue>
-bool RBTree<TKey, TValue>::contains(const TKey& key) const
-{
-	Node* n = inner_find(key);
-
-	if (n == m_sentinel || !(n->item.key == key))
-	{
-		return false;
-	}
-
-	return true;
-}
-
-/* Inner utilities */
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::inner_find(TKey key) const
-{
-	Node* x = m_root;
-
-	while (x != m_sentinel)
-	{
-		if (key > x->item.key)
-		{
-			if (x->right == m_sentinel)
-			{
-				return x;
-			}
-
-			x = x->right;
-		}
-		else if (key < x->item.key)
-		{
-			if (x->left == m_sentinel)
-			{
-				return x;
-			}
-
-			x = x->left;
-		}
-		else
-		{
-			break;
-		}
-	}
-
-	return x;
-}
-
-template<typename TKey, typename TValue>
-void RBTree<TKey, TValue>::add_fixup(Node* n)
-{
-	Node* x;
-	Node* y;
-
-	while (n!=m_root && n->parent->color==RED)
-	{
-		x = n->parent;
-
-		if (x == x->parent->left)
-		{
-			y = x->parent->right;
-
-			if (y->color == RED)
-			{
-				x->color = BLACK;
-				y->color = BLACK;
-				x->parent->color = RED;
-				n = x->parent;
-				continue;
-			}
-			else
-			{
-				if (n == x->right)
-				{
-					n = x;
-					rotate_left(n);
-					x = n->parent;
-				}
-
-				x->color = BLACK;
-				x->parent->color = RED;
-				rotate_right(x->parent);
-			}
-		}
-		else
-		{
-			y = x->parent->left;
-
-			if (y->color == RED)
-			{
-				x->color = BLACK;
-				y->color = BLACK;
-				x->parent->color = RED;
-				n = x->parent;
-				continue;
-			}
-			else
-			{
-				if (n == x->left)
-				{
-					n = x;
-					rotate_right(n);
-					x = n->parent;
-				}
-
-				x->color = BLACK;
-				x->parent->color = RED;
-				rotate_left(x->parent);
-			}
-		}
-	}
-}
-
-template<typename TKey, typename TValue>
-void RBTree<TKey, TValue>::inner_clear(Node* n)
-{
-	if (n == m_sentinel)
-	{
-		return;
-	}
-
-	Node* tmp;
-	
-	tmp = n->left;
-	n->left = NULL;
-	inner_clear(tmp);
-
-	tmp = n->right;
-	n->right = NULL;
-	inner_clear(tmp);
-
-	CE_DELETE(m_allocator, n);
-}
-
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::predecessor(Node* x) const
-{
-	if (x->left != m_sentinel)
-	{
-		return max(x->left);
-	}
-
-	Node* y = x->parent;
-
-	while (y != NULL && x == y->left)
-	{
-		x = y;
-		y = y->parent;
-	}
-
-	return y;
-}
-
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::successor(Node* x) const
-{
-	if (x->right != m_sentinel)
-	{
-		return min(x->right);
-	}
-
-	Node* y = x->parent;
-
-	while (y != NULL && x == y->right)
-	{
-		x = y;
-		y = y->parent;
-	}
-
-	return y;
-}
-
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::min(Node* x) const
-{
-	if (x == m_sentinel)
-	{
-		return x;
-	}
-
-	while (x->left != m_sentinel)
-	{
-		x = x->left;
-	}
-
-	return x;
-}
-
-template<typename TKey, typename TValue>
-RBTreeNode<TKey, TValue>* RBTree<TKey, TValue>::max(Node* x) const
-{
-	if (x == m_sentinel)
-	{
-		return x;
-	}
-
-	while (x->right != m_sentinel)
-	{
-		x = x->right;
-	}
-
-	return x;
-}
-
-template<typename TKey, typename TValue>
-inline void RBTree<TKey, TValue>::rotate_left(Node* x)
-{
-	Node* y = x->right;
-	x->right = y->left;
-
-	if (y->left != m_sentinel)
-	{
-		y->left->parent = x;
-	}
-
-	y->parent = x->parent;
-
-	if (x->parent == NULL)
-	{
-		m_root = y;
-	}
-	else
-	{
-		if (x == x->parent->left)
-		{
-			x->parent->left = y;
-		}
-		else
-		{
-			x->parent->right = y;
-		}
-	}
-
-	y->left = x;
-	x->parent = y;
-}
-
-template<typename TKey, typename TValue>
-inline void RBTree<TKey, TValue>::rotate_right(Node* x)
-{
-	Node* y = x->left;
-	x->left = y->right;
-
-	if (y->right != m_sentinel)
-	{
-		y->right->parent = x;
-	}
-
-	y->parent = x->parent;
-
-	if (x->parent == NULL)
-	{
-		m_root = y;
-	}
-	else
-	{
-		if (x == x->parent->left)
-		{
-			x->parent->left = y;
-		}
-		else
-		{
-			x->parent->right = y;
-		}
-	}
-
-	y->right = x;
-	x->parent = y;
-}
-
-#ifdef RBTREE_VERIFY
-template<typename TKey, typename TValue>
-int32_t RBTree<TKey, TValue>::dbg_verify(Node* n) const
-{
-	if (n == m_sentinel)
-	{
-		return 0;
-	}
-
-	if (n->left != m_sentinel)
-	{
-		CE_ASSERT(n->left->parent == n);
-		CE_ASSERT(n->item.key > n->left->item.key);
-	}
-
-	if (n->right != m_sentinel)
-	{
-		CE_ASSERT(n->right->parent == n);
-		CE_ASSERT(n->item.key < n->right->item.key);
-	}
-
-	int32_t bhL = dbg_verify(n->left);
-	int32_t bhR = dbg_verify(n->right);
-	CE_ASSERT(bhL == bhR);
-
-	if (n->color == BLACK)
-	{
-		bhL += 1;
-	}
-	else
-	{
-		if (n->parent != NULL && n->parent->color == RED)
-		{
-			CE_ASSERT(false);
-		}
-	}
-
-	return bhL;
-}
-#endif
-
-} // namespace crown
-

+ 1 - 1
engine/core/containers/Vector.h

@@ -278,7 +278,7 @@ inline Vector<T>::Vector(Allocator& allocator, uint32_t capacity)
 //-----------------------------------------------------------------------------
 template <typename T>
 inline Vector<T>::Vector(const Vector<T>& other)
-	: m_array(other.m_array.allocator)
+	: m_array(other.m_array)
 {
 	*this = other;
 }

+ 5 - 6
engine/core/json/JSON.cpp

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "ContainerTypes.h"
 #include "StringUtils.h"
 #include "DynamicString.h"
+#include "Map.h"
 
 namespace crown
 {
@@ -429,7 +430,7 @@ namespace json
 	}
 
 	//-----------------------------------------------------------------------------
-	void parse_object(const char* s, Array<JSONPair>& object)
+	void parse_object(const char* s, Map<DynamicString, const char*>& object)
 	{
 		CE_ASSERT_NOT_NULL(s);
 
@@ -449,9 +450,8 @@ namespace json
 
 			while (*ch)
 			{
-				JSONPair pair;
-
-				pair.key = ch;
+				DynamicString key;
+				parse_string(ch, key);
 
 				// Skip any value
 				ch = skip_array(ch);
@@ -465,8 +465,7 @@ namespace json
 				ch = next(ch, ':');
 				ch = skip_whites(ch);
 
-				pair.val = ch;
-				array::push_back(object, pair);
+				map::set(object, key, ch);
 
 				// Skip any value
 				ch = skip_array(ch);

+ 4 - 12
engine/core/json/JSON.h

@@ -26,6 +26,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "DynamicString.h"
+#include "ContainerTypes.h"
 
 #pragma once
 
@@ -50,15 +51,6 @@ struct JSONType
 	};
 };
 
-/// Represents a key-value pair in a JSON document.
-///
-/// @ingroup JSON
-struct JSONPair
-{
-	const char* key;
-	const char* val;
-};
-
 /// Functions to parse JSON-encoded strings.
 ///
 /// @ingroup JSON
@@ -86,8 +78,8 @@ namespace json
 	/// the corresponding items into the original @a s string.
 	void parse_array(const char* s, Array<const char*>& array);
 
-	/// Parses the @a s JSON object and puts it into @a object as pointers to
-	/// the corresponding key/value pairs into the original @a s string.
-	void parse_object(const char* s, Array<JSONPair>& object);
+	/// Parses the JSON object @a s and puts it into @a object as map from
+	/// key to pointer to the corresponding value into the original string @a s.
+	void parse_object(const char* s, Map<DynamicString, const char*>& object);
 } // namespace json
 } // namespace crown

+ 19 - 90
engine/core/json/JSONParser.cpp

@@ -28,7 +28,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "JSON.h"
 #include "TempAllocator.h"
 #include "StringUtils.h"
-#include "Log.h"
+#include "Vector.h"
+#include "Map.h"
 
 namespace crown
 {
@@ -100,28 +101,13 @@ JSONElement JSONElement::index_or_nil(uint32_t i)
 //--------------------------------------------------------------------------
 JSONElement JSONElement::key(const char* k)
 {
-	Array<JSONPair> object(default_allocator());
-
+	Map<DynamicString, const char*> object(default_allocator());
 	json::parse_object(m_at, object);
 
-	bool found = false;
-
-	const char* tmp_at = m_at;
-	for (uint32_t i = 0; i < array::size(object); i++)
-	{
-		DynamicString key;
-		json::parse_string(object[i].key, key);
-
-		if (key == k)
-		{
-			tmp_at = object[i].val;
-			found = true;
-		}
-	}
-
-	CE_ASSERT(found, "Key not found: '%s'", k);
+	const char* value = map::get(object, DynamicString(k), (const char*) NULL);
+	CE_ASSERT(value != NULL, "Key not found: '%s'", k);
 
-	return JSONElement(tmp_at);
+	return JSONElement(value);
 }
 
 //--------------------------------------------------------------------------
@@ -129,31 +115,13 @@ JSONElement JSONElement::key_or_nil(const char* k)
 {
 	if (m_at != NULL)
 	{
-		Array<JSONPair> object(default_allocator());
-
+		Map<DynamicString, const char*> object(default_allocator());
 		json::parse_object(m_at, object);
 
-		bool found = false;
+		const char* value = map::get(object, DynamicString(k), (const char*) NULL);
 
-		const char* tmp_at = m_at;
-		for (uint32_t i = 0; i < array::size(object); i++)
-		{
-			DynamicString key;
-			json::parse_string(object[i].key, key);
-
-			if (key == k)
-			{
-				tmp_at = object[i].val;
-				found = true;
-			}
-		}
-
-		if (!found)
-		{
-			return JSONElement();
-		}
-
-		return JSONElement(tmp_at);
+		if (value)
+			return JSONElement(value);
 	}
 
 	return JSONElement();
@@ -162,48 +130,10 @@ JSONElement JSONElement::key_or_nil(const char* k)
 //--------------------------------------------------------------------------
 bool JSONElement::has_key(const char* k) const
 {
-	Array<JSONPair> object(default_allocator());
-	json::parse_object(m_at, object);
-
-	for (uint32_t i = 0; i < array::size(object); i++)
-	{
-		DynamicString key;
-		json::parse_string(object[i].key, key);
-
-		if (key == k)
-		{
-			return true;
-		}
-	}
-
-	return false;
-}
-
-//--------------------------------------------------------------------------
-bool JSONElement::is_key_unique(const char* k) const
-{
-	Array<JSONPair> object(default_allocator());
+	Map<DynamicString, const char*> object(default_allocator());
 	json::parse_object(m_at, object);
 
-	bool found = false;
-
-	for (uint32_t i = 0; i < array::size(object); i++)
-	{
-		DynamicString key;
-		json::parse_string(object[i].key, key);
-
-		if (key == k)
-		{
-			if (found == true)
-			{
-				return false;
-			}
-
-			found = true;
-		}
-	}
-
-	return found;
+	return map::has(object, DynamicString(k));
 }
 
 //--------------------------------------------------------------------------
@@ -338,14 +268,14 @@ void JSONElement::to_array(Vector<DynamicString>& array) const
 //--------------------------------------------------------------------------
 void JSONElement::to_keys(Vector<DynamicString>& keys) const
 {
-	Array<JSONPair> object(default_allocator());
+	Map<DynamicString, const char*> object(default_allocator());
 	json::parse_object(m_at, object);
 
-	for (uint32_t i = 0; i < array::size(object); i++)
+	const typename Map<DynamicString, const char*>::Node* it = map::begin(object);
+	while (it != map::end(object))
 	{
-		DynamicString key;
-		json::parse_string(object[i].key, key);
-		vector::push_back(keys, key);
+		vector::push_back(keys, (*it).key);
+		it++;
 	}
 }
 
@@ -431,10 +361,9 @@ uint32_t JSONElement::size() const
 		}
 		case JSONType::OBJECT:
 		{
-			Array<JSONPair> object(default_allocator());
+			Map<DynamicString, const char*> object(default_allocator());
 			json::parse_object(m_at, object);
-
-			return array::size(object);
+			return map::size(object);
 		}
 		case JSONType::ARRAY:
 		{

+ 0 - 5
engine/core/json/JSONParser.h

@@ -28,7 +28,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "ContainerTypes.h"
-#include "Vector.h"
 
 namespace crown
 {
@@ -78,10 +77,6 @@ public:
 	/// Returns whether the element has the @a k key.
 	bool				has_key(const char* k) const;
 
-	/// Returns whether the @a k key is unique in the object
-	/// element. If no such key is found it returns false.
-	bool				is_key_unique(const char* k) const;
-
 	/// Returns true wheter the element is the JSON nil special value.
 	bool				is_nil() const;
 

+ 47 - 44
engine/core/strings/DynamicString.h

@@ -43,56 +43,58 @@ class DynamicString
 {
 public:
 
-						DynamicString(Allocator& allocator = default_allocator());
-						DynamicString(const char* s, Allocator& allocator = default_allocator());
+	DynamicString(Allocator& allocator = default_allocator());
+	DynamicString(const char* s, Allocator& allocator = default_allocator());
 
-						~DynamicString();
+	~DynamicString();
 
-	DynamicString&		operator+=(DynamicString& s);
-	DynamicString&		operator+=(const char* s);
-	DynamicString&		operator+=(const char c);
+	DynamicString& operator+=(const DynamicString& s);
+	DynamicString& operator+=(const char* s);
+	DynamicString& operator+=(const char c);
 	///
-	DynamicString&		operator=(DynamicString& s);
-	DynamicString&		operator=(const char* s);
-	DynamicString&		operator=(const char c);
+	DynamicString& operator=(const DynamicString& s);
+	DynamicString& operator=(const char* s);
+	DynamicString& operator=(const char c);
 
-	bool				operator==(DynamicString& s);
-	bool				operator==(const char* s);
+	bool operator<(const DynamicString& s) const;
+	bool operator==(const DynamicString& s) const;
+	bool operator==(const char* s) const;
 
 	// Returns the length of the string.
-	uint32_t			length();
+	uint32_t length() const;
 
 	/// Removes the leading string @a s.
 	/// @note
 	/// The string must start with @a s.
-	void				strip_leading(const char* s);
+	void strip_leading(const char* s);
 
 	/// Removes the trailing string @a s.
 	/// @note
 	/// The string must end with @a s.
-	void				strip_trailing(const char* s);
+	void strip_trailing(const char* s);
 
 	/// Returns whether the string starts with the given @a s string.
-	bool				starts_with(const char* s);
+	bool starts_with(const char* s) const;
 
 	/// Returns wheterh the string ends with the given @æ s string.
-	bool				ends_with(const char* s);
+	bool ends_with(const char* s) const;
 
 	/// Returns the string hashed to string::murmur2_32.
-	StringId32			to_string_id();
+	StringId32 to_string_id() const;
 
 	///
-	const char*			c_str();
+	const char* c_str() const;
 
 private:
 
-	Array<char>			m_string;
+	Array<char> m_string;
 };
 
 //-----------------------------------------------------------------------------
 inline DynamicString::DynamicString(Allocator& allocator)
 	: m_string(allocator)
 {
+	array::push_back(m_string, '\0');
 }
 
 //-----------------------------------------------------------------------------
@@ -103,6 +105,7 @@ inline DynamicString::DynamicString(const char* s, Allocator& allocator)
 	{
 		array::push(m_string, s, string::strlen(s));
 	}
+	array::push_back(m_string, '\0');
 }
 
 //-----------------------------------------------------------------------------
@@ -111,47 +114,44 @@ inline DynamicString::~DynamicString()
 }
 
 //-----------------------------------------------------------------------------
-inline DynamicString& DynamicString::operator+=(DynamicString& s)
+inline DynamicString& DynamicString::operator+=(const DynamicString& s)
 {
-	const char* tmp = s.c_str();
-
-	return *this += tmp;
+	return *this += s.c_str();
 }
 
 //-----------------------------------------------------------------------------
 inline DynamicString& DynamicString::operator+=(const char* s)
 {
 	CE_ASSERT_NOT_NULL(s);
-
+	array::pop_back(m_string);
 	array::push(m_string, s, string::strlen(s));
-
+	array::push_back(m_string, '\0');
 	return *this;
 }
 
 //-----------------------------------------------------------------------------
 inline DynamicString& DynamicString::operator+=(const char c)
 {
+	array::pop_back(m_string);
 	array::push_back(m_string, c);
-
+	array::push_back(m_string, '\0');
 	return *this;
 }
 
 //-----------------------------------------------------------------------------
-inline DynamicString& DynamicString::operator=(DynamicString& s)
+inline DynamicString& DynamicString::operator=(const DynamicString& s)
 {
-	const char* tmp = s.c_str();
-
-	return *this = tmp;
+	m_string = s.m_string;
+	return *this;
 }
 
 //-----------------------------------------------------------------------------
 inline DynamicString& DynamicString::operator=(const char* s)
 {
 	CE_ASSERT_NOT_NULL(s);
-
 	array::clear(m_string);
 	array::push(m_string, s, string::strlen(s));
-
+	array::push_back(m_string, '\0');
 	return *this;
 }
 
@@ -165,13 +165,19 @@ inline DynamicString& DynamicString::operator=(const char c)
 }
 
 //-----------------------------------------------------------------------------
-inline bool DynamicString::operator==(DynamicString& s)
+inline bool DynamicString::operator<(const DynamicString& s) const
+{
+	return string::strcmp(c_str(), s.c_str()) < 0;
+}
+
+//-----------------------------------------------------------------------------
+inline bool DynamicString::operator==(const DynamicString& s) const
 {
 	return string::strcmp(c_str(), s.c_str()) == 0;
 }
 
 //-----------------------------------------------------------------------------
-inline bool DynamicString::operator==(const char* s)
+inline bool DynamicString::operator==(const char* s) const
 {
 	CE_ASSERT_NOT_NULL(s);
 
@@ -179,7 +185,7 @@ inline bool DynamicString::operator==(const char* s)
 }
 
 //-----------------------------------------------------------------------------
-inline uint32_t DynamicString::length()
+inline uint32_t DynamicString::length() const
 {
 	return string::strlen(this->c_str());
 }
@@ -195,6 +201,7 @@ inline void DynamicString::strip_leading(const char* s)
 
 	memmove(array::begin(m_string), array::begin(m_string) + s_len, (my_len - s_len));
 	array::resize(m_string, my_len - s_len);
+	array::push_back(m_string, '\0');
 }
 
 //-----------------------------------------------------------------------------
@@ -205,20 +212,19 @@ inline void DynamicString::strip_trailing(const char* s)
 
 	const size_t my_len = string::strlen(c_str());
 	const size_t s_len = string::strlen(s);
-
 	array::resize(m_string, my_len - s_len);
+	array::push_back(m_string, '\0');
 }
 
 //-----------------------------------------------------------------------------
-inline bool DynamicString::starts_with(const char* s)
+inline bool DynamicString::starts_with(const char* s) const
 {
 	CE_ASSERT_NOT_NULL(s);
-
 	return string::strncmp(c_str(), s, string::strlen(s)) == 0;
 }
 
 //-----------------------------------------------------------------------------
-inline bool DynamicString::ends_with(const char* s)
+inline bool DynamicString::ends_with(const char* s) const
 {
 	CE_ASSERT_NOT_NULL(s);
 
@@ -234,17 +240,14 @@ inline bool DynamicString::ends_with(const char* s)
 }
 
 //-----------------------------------------------------------------------------
-inline StringId32 DynamicString::to_string_id()
+inline StringId32 DynamicString::to_string_id() const
 {
 	return string::murmur2_32(c_str(), length());
 }
 
 //-----------------------------------------------------------------------------
-inline const char* DynamicString::c_str()
+inline const char* DynamicString::c_str() const
 {
-	array::push_back(m_string, '\0');
-	array::pop_back(m_string);
-
 	return array::begin(m_string);
 }
 

+ 19 - 0
engine/lua/LuaEnvironment.cpp

@@ -165,4 +165,23 @@ void LuaEnvironment::call_global(const char* func, uint8_t argc, ...)
 	lua_pcall(m_L, argc, 0, -argc - 2);
 }
 
+void LuaEnvironment::call_physics_callback(Actor* actor_0, Actor* actor_1, Unit* unit_0, Unit* unit_1, const Vector3& where, const Vector3& normal, const char* type)
+{
+	LuaStack stack(m_L);
+
+	lua_pushcfunction(m_L, lua_system::error_handler);
+	lua_getglobal(m_L, "physics_callback");
+
+	stack.push_table();
+	stack.push_key_begin("actor_0"); stack.push_actor(actor_0); stack.push_key_end();
+	stack.push_key_begin("actor_1"); stack.push_actor(actor_1); stack.push_key_end();
+	stack.push_key_begin("unit_0"); stack.push_unit(unit_0); stack.push_key_end();
+	stack.push_key_begin("unit_1"); stack.push_unit(unit_1); stack.push_key_end();
+	stack.push_key_begin("where"); stack.push_vector3(where); stack.push_key_end();
+	stack.push_key_begin("normal"); stack.push_vector3(normal); stack.push_key_end();
+	stack.push_key_begin("type"); stack.push_string(type); stack.push_key_end();
+
+	lua_pcall(m_L, 1, 0, -3);
+}
+
 } // namespace crown

+ 9 - 0
engine/lua/LuaEnvironment.h

@@ -31,6 +31,9 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Types.h"
 #include "Macros.h"
 
+// HACK
+#include "MathTypes.h"
+
 namespace crown
 {
 
@@ -40,6 +43,9 @@ enum LuaArgumentType
 };
 
 struct LuaResource;
+// HACK
+struct Actor;
+struct Unit;
 
 /// LuaEnvironment is a wrapper of a subset of Lua functions and 
 /// provides utilities for extending Lua
@@ -70,6 +76,9 @@ public:
 	/// Returns true if success, false otherwise
 	void call_global(const char* func, uint8_t argc, ...);
 
+	// HACK
+	void call_physics_callback(Actor* actor_0, Actor* actor_1, Unit* unit_0, Unit* unit_1, const Vector3& where, const Vector3& normal, const char* type);
+
 private:
 
 	// Disable copying

+ 2 - 2
engine/lua/LuaPhysicsWorld.cpp

@@ -65,7 +65,7 @@ static int physics_world_make_raycast(lua_State* L)
 	int mode = stack.get_int(3);
 	int filter = stack.get_int(4);
 
-	RaycastId raycast = world->create_raycast(callback, (CollisionMode::Enum) mode, (CollisionType::Enum) filter);
+	RaycastId raycast = world->create_raycast((CollisionMode::Enum) mode, (CollisionType::Enum) filter);
 
 	stack.push_raycast(world->lookup_raycast(raycast));
 	return 1;
@@ -86,7 +86,7 @@ static int physics_world_overlap_test(lua_State* L)
 
 	Array<Actor*> actors(default_allocator());
 
-	world->overlap_test(callback, filter, shape_type, pos, rot, size, actors);
+	world->overlap_test(filter, shape_type, pos, rot, size, actors);
 
 	stack.push_table();
 	for (uint32_t i = 0; i < array::size(actors); i++)

+ 14 - 0
engine/lua/LuaQuaternion.cpp

@@ -150,6 +150,19 @@ static int quaternion_power(lua_State* L)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+static int quaternion_elements(lua_State* L)
+{
+	LuaStack stack(L);
+	const Quaternion& q = stack.get_quaternion(1);
+
+	stack.push_float(q.x);
+	stack.push_float(q.y);
+	stack.push_float(q.z);
+	stack.push_float(q.w);
+	return 4;
+}
+
 //-----------------------------------------------------------------------------
 void load_quaternion(LuaEnvironment& env)
 {
@@ -162,6 +175,7 @@ void load_quaternion(LuaEnvironment& env)
 	env.load_module_function("Quaternion", "conjugate",				quaternion_conjugate);
 	env.load_module_function("Quaternion", "inverse",				quaternion_inverse);
 	env.load_module_function("Quaternion", "power",					quaternion_power);
+	env.load_module_function("Quaternion", "elements",				quaternion_elements);
 
 	env.load_module_constructor("Quaternion",						quaternion_ctor);
 }

+ 16 - 18
engine/lua/LuaQuaternionBox.cpp

@@ -38,20 +38,19 @@ static int quaternionbox_new(lua_State* L)
 	LuaStack stack(L);
 
 	Quaternion q;
+	if (stack.num_args() == 1)
+	{
+		q = stack.get_quaternion(1);
+	}
 	if (stack.num_args() == 2)
 	{
-		const Vector3& v = stack.get_vector3(1);
-		q.x = v.x;
-		q.y = v.y;
-		q.z = v.z;
-		q.w = stack.get_float(2);
+		Quaternion quat(stack.get_vector3(1), stack.get_float(2));
+		q = quat;
 	}
 	else if (stack.num_args() == 4)
 	{
-		q.x = stack.get_float(1);
-		q.y = stack.get_float(2);
-		q.z = stack.get_float(3);
-		q.w = stack.get_float(4);
+		Quaternion quat(stack.get_float(1), stack.get_float(2),	stack.get_float(3),	stack.get_float(4));
+		q = quat;
 	}
 
 	stack.push_quaternionbox(q);
@@ -73,20 +72,19 @@ static int quaternionbox_store(lua_State* L)
 
 	Quaternion& q = stack.get_quaternionbox(1);
 	
+	if (stack.num_args() == 2)
+	{
+		q = stack.get_quaternion(2);
+	}
 	if (stack.num_args() == 3)
 	{
-		const Vector3& v = stack.get_vector3(1);
-		q.x = v.x;
-		q.y = v.y;
-		q.z = v.z;
-		q.w = stack.get_float(2);
+		Quaternion quat(stack.get_vector3(2), stack.get_float(3));
+		q = quat;
 	}
 	else if (stack.num_args() == 5)
 	{
-		q.x = stack.get_float(1);
-		q.y = stack.get_float(2);
-		q.z = stack.get_float(3);
-		q.w = stack.get_float(4);
+		Quaternion quat(stack.get_float(2), stack.get_float(3),	stack.get_float(4),	stack.get_float(5));
+		q = quat;
 	}
 	return 0;
 }

+ 43 - 35
engine/physics/PhysicsCallback.h

@@ -55,6 +55,8 @@ using physx::PxVec3;
 using physx::PxRaycastCallback;
 using physx::PxAgain;
 using physx::PxRaycastHit;
+using physx::PxPairFlag;
+using physx::PxContactPairFlag;
 
 namespace crown
 {
@@ -81,51 +83,62 @@ public:
 	//-----------------------------------------------------------------------------
 	void onContact(const PxContactPairHeader& pair_header, const PxContactPair* pairs, PxU32 num_pairs)
 	{
-		// printf("CONTACT\n");
+		// Do not report contact if either actor0 or actor1 or both have been deleted
+		if (pair_header.flags & PxContactPairHeaderFlag::eDELETED_ACTOR_0 ||
+			pair_header.flags & PxContactPairHeaderFlag::eDELETED_ACTOR_1) return;
 
-		// Do not report contact if either actor0 or actor1 has been deleted
-		if (pair_header.flags & PxContactPairHeaderFlag::eDELETED_ACTOR_0 || pair_header.flags & PxContactPairHeaderFlag::eDELETED_ACTOR_1) return;
-
-		// printf("ACTOR0 = %.4X\n", pair_header.actors[0]->userData);
-		// printf("ACTOR1 = %.4X\n", pair_header.actors[1]->userData);
-
-		PxVec3 where;
-
-		// printf("Num pairs = %d\n", num_pairs);
 		for (PxU32 pp = 0; pp < num_pairs; pp++)
 		{
-			PxContactPairPoint points[8];
-			const PxU32 num_points = pairs[pp].extractContacts(points, 8);
-			// printf("Num points = %d\n", num_points);
+			const PxContactPair& cp = pairs[pp];
+
+			// We are only interested in touch found or lost
+			if (!cp.events & PxPairFlag::eNOTIFY_TOUCH_FOUND ||
+				!cp.events & PxPairFlag::eNOTIFY_TOUCH_LOST) continue;
 
+			// Skip if either shape0 or shape1 or both have been deleted
+			if (cp.flags & PxContactPairFlag::eDELETED_SHAPE_0 ||
+				cp.flags & PxContactPairFlag::eDELETED_SHAPE_1) continue;
+			
+			PxContactPairPoint points[8];
+			const PxU32 num_points = cp.extractContacts(points, 8);
+			
+			PxVec3 where;
+			PxVec3 normal;
 			for (PxU32 i = 0; i < num_points; i++)
 			{
 				where = points[i].position;
-				// printf("where = %.2f %.2f %.2f\n", where.x, where.y, where.z);
+				normal = points[i].normal;
 			}
-		}
 
-		physics_world::CollisionEvent ev;
-		ev.actors[0] = (Actor*) pair_header.actors[0]->userData;
-		ev.actors[1] = (Actor*) pair_header.actors[1]->userData;
-		ev.where = Vector3(where.x, where.y, where.z);
-		event_stream::write(m_events, physics_world::EventType::COLLISION, ev);
+			physics_world::CollisionEvent ev;
+			ev.type = (cp.events & PxPairFlag::eNOTIFY_TOUCH_FOUND) ?
+						physics_world::CollisionEvent::BEGIN_TOUCH :
+						physics_world::CollisionEvent::END_TOUCH;
+			ev.actors[0] = (Actor*) pair_header.actors[0]->userData;
+			ev.actors[1] = (Actor*) pair_header.actors[1]->userData;
+			ev.where = Vector3(where.x, where.y, where.z);
+			ev.normal = Vector3(normal.x, normal.y, normal.z);
+			event_stream::write(m_events, physics_world::EventType::COLLISION, ev);
+		}
 	}
 
 	//-----------------------------------------------------------------------------
 	void onTrigger(PxTriggerPair* pairs, PxU32 count)
 	{
-		// printf("TRIGGER\n");
-		// printf("Num pairs = %d\n", count);
-
 		for (PxU32 pp = 0; pp < count; pp++)
 		{
-			const PxTriggerPair& pair = pairs[pp];
-			// Do not report event if either trigger ot other shape has been deleted
-			if (pair.flags & PxTriggerPairFlag::eDELETED_SHAPE_TRIGGER || pair.flags & PxTriggerPairFlag::eDELETED_SHAPE_OTHER) continue;
+			const PxTriggerPair& tp = pairs[pp];
+
+			// Do not report event if either trigger ot other shape or both have been deleted
+			if (tp.flags & PxTriggerPairFlag::eDELETED_SHAPE_TRIGGER ||
+				tp.flags & PxTriggerPairFlag::eDELETED_SHAPE_OTHER) continue;
 
-			// TODO
 			physics_world::TriggerEvent ev;
+			ev.type = (tp.status & PxPairFlag::eNOTIFY_TOUCH_FOUND ?
+						physics_world::TriggerEvent::BEGIN_TOUCH : physics_world::TriggerEvent::END_TOUCH);
+			ev.trigger = (Actor*) tp.triggerActor->userData;
+			ev.other = (Actor*) tp.otherActor->userData;
+
 			event_stream::write(m_events, physics_world::EventType::TRIGGER, ev);
 		}
 	}
@@ -133,13 +146,11 @@ public:
 	//-----------------------------------------------------------------------------
 	void onWake(PxActor** /*actors*/, PxU32 /*count*/)
 	{
-		// printf("WAKE\n");
 	}
 
 	//-----------------------------------------------------------------------------
 	void onSleep(PxActor** /*actors*/, PxU32 /*count*/)
 	{
-		// printf("SLEEP\n");
 	}
 
 private:
@@ -151,21 +162,18 @@ private:
 class PhysicsControllerCallback : public PxUserControllerHitReport
 {
 	//-----------------------------------------------------------------------------
-	void onShapeHit(const PxControllerShapeHit& hit)
+	void onShapeHit(const PxControllerShapeHit& /*hit*/)
 	{
-		// printf("SHAPE HIT\n");
 	}
 
 	//-----------------------------------------------------------------------------
-	void onControllerHit(const PxControllersHit& hit)
+	void onControllerHit(const PxControllersHit& /*hit*/)
 	{
-		// printf("CONTROLLER HIT\n");
 	}
 
 	//-----------------------------------------------------------------------------
-	void onObstacleHit(const PxControllerObstacleHit& hit)
+	void onObstacleHit(const PxControllerObstacleHit& /*hit*/)
 	{
-		// printf("OBSTACLE HIT\n");
 	}
 };
 

+ 5 - 1
engine/physics/PhysicsTypes.h

@@ -157,14 +157,18 @@ struct EventType
 //-----------------------------------------------------------------------------
 struct CollisionEvent
 {
+	enum { BEGIN_TOUCH, END_TOUCH } type;
 	Actor* actors[2];
 	Vector3 where;
+	Vector3 normal;
 };
 
 //-----------------------------------------------------------------------------
 struct TriggerEvent
 {
-	Actor* actor;
+	enum { BEGIN_TOUCH, END_TOUCH } type;
+	Actor* trigger;
+	Actor* other;
 };
 
 } // namespace physics_world

+ 8 - 6
engine/physics/PhysicsWorld.cpp

@@ -154,7 +154,7 @@ namespace physics_system
 		// let triggers through
 		if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
 		{
-			pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
+			pairFlags = PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST;
 			return PxFilterFlag::eDEFAULT;
 		}
 
@@ -163,9 +163,11 @@ namespace physics_system
 
 		// trigger the contact callback for pairs (A,B) where 
 		// the filtermask of A contains the ID of B and vice versa.
-		if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
+		//if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
 		{
-			pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_CONTACT_POINTS;
+			pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND
+						| PxPairFlag::eNOTIFY_TOUCH_LOST
+						| PxPairFlag::eNOTIFY_CONTACT_POINTS;
 			return PxFilterFlag::eDEFAULT;
 		}
 
@@ -311,9 +313,9 @@ void PhysicsWorld::destroy_joint(JointId id)
 }
 
 //-----------------------------------------------------------------------------
-RaycastId PhysicsWorld::create_raycast(const char* callback, CollisionMode::Enum mode, CollisionType::Enum filter)
+RaycastId PhysicsWorld::create_raycast(CollisionMode::Enum mode, CollisionType::Enum filter)
 {
-	Raycast* raycast = CE_NEW(m_raycasts_pool, Raycast)(m_scene, m_events, callback, mode, filter);
+	Raycast* raycast = CE_NEW(m_raycasts_pool, Raycast)(m_scene, mode, filter);
 	return m_raycasts.create(raycast);
 }
 
@@ -389,7 +391,7 @@ void PhysicsWorld::clear_kinematic(ActorId id)
 }
 
 //-----------------------------------------------------------------------------
-void PhysicsWorld::overlap_test(const char* callback, CollisionType::Enum filter, ShapeType::Enum type,
+void PhysicsWorld::overlap_test(CollisionType::Enum filter, ShapeType::Enum type,
 								const Vector3& pos, const Quaternion& rot, const Vector3& size, Array<Actor*>& actors)
 {
 	PxTransform transform(PxVec3(pos.x, pos.y, pos.z), PxQuat(rot.x, rot.y, rot.z, rot.w));

+ 6 - 3
engine/physics/PhysicsWorld.h

@@ -58,6 +58,8 @@ namespace crown
 /// @defgroup Physics Physics
 
 /// Global physics-related functions
+///
+/// @ingroup Physics
 namespace physics_system
 {
 	/// Initializes the physics system.
@@ -94,7 +96,7 @@ public:
 	JointId create_joint(const PhysicsResource* pr, const uint32_t index, const Actor& actor_0, const Actor& actor_1);
 	void destroy_joint(JointId id);
 
-	RaycastId create_raycast(const char* callback, CollisionMode::Enum mode, CollisionType::Enum filter);
+	RaycastId create_raycast(CollisionMode::Enum mode, CollisionType::Enum filter);
 	void destroy_raycast(RaycastId id);
 
 
@@ -105,8 +107,8 @@ public:
 	void clear_kinematic(ActorId id);
 
 	/// Finds all actors in the physics world that are in a particular shape (supported: spheres, capsules and boxes)
-	void overlap_test(const char* callback, CollisionType::Enum filter, ShapeType::Enum type,
-											const Vector3& pos, const Quaternion& rot, const Vector3& size, Array<Actor*>& actors);
+	void overlap_test(CollisionType::Enum filter, ShapeType::Enum type,
+						const Vector3& pos, const Quaternion& rot, const Vector3& size, Array<Actor*>& actors);
 
 	void update(float dt);
 
@@ -116,6 +118,7 @@ public:
 	Raycast* lookup_raycast(RaycastId id);
 
 	World& world() { return m_world; }
+	EventStream& events() { return m_events; }
 
 public:
 

+ 1 - 3
engine/physics/Raycast.cpp

@@ -35,11 +35,9 @@ namespace crown
 {
 
 //-------------------------------------------------------------------------
-Raycast::Raycast(PxScene* scene, EventStream& events, const char* callback, CollisionMode::Enum mode, CollisionType::Enum type)
+Raycast::Raycast(PxScene* scene, CollisionMode::Enum mode, CollisionType::Enum type)
 	: m_scene(scene)
 	, m_buffer(m_hits, CE_MAX_RAY_INTERSECTIONS)
-	, m_events(events)
-	, m_callback(callback)
 	, m_mode(mode)
 	, m_type(type)
 {

+ 3 - 6
engine/physics/Raycast.h

@@ -56,12 +56,13 @@ struct RaycastHit
 	Actor*					actor;
 };
 
+
 ///
 /// @ingroup Physics
 struct Raycast
 {
 	/// Constructor
-	Raycast(PxScene* scene, EventStream& events, const char* callback, CollisionMode::Enum mode, CollisionType::Enum type);
+	Raycast(PxScene* scene, CollisionMode::Enum mode, CollisionType::Enum type);
 
 	/// Performs a raycast against objects in the scene. The ray is casted from position @a from, has direction @a dir and is long @a length
 	/// If any actor is hit along the ray, @a EventStream is filled according to @a mode previously specified and callback will be called for processing.
@@ -79,13 +80,9 @@ struct Raycast
 private:
 
 	PxScene* 				m_scene;
-	PxRaycastHit 			m_hits[CE_MAX_RAY_INTERSECTIONS];	
+	PxRaycastHit 			m_hits[CE_MAX_RAY_INTERSECTIONS];
 	PxRaycastBuffer			m_buffer;
 	PxQueryFilterData 		m_fd;
-
-	EventStream&			m_events;
-	const char*				m_callback;
-
 	CollisionMode::Enum		m_mode;
 	CollisionType::Enum		m_type;
 };

+ 70 - 0
engine/world/World.cpp

@@ -30,6 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Device.h"
 #include "ResourceManager.h"
 #include "DebugLine.h"
+#include "Actor.h"
+#include "LuaEnvironment.h"
 
 namespace crown
 {
@@ -162,6 +164,8 @@ void World::update(float dt)
 	m_scenegraph_manager.update();
 
 	m_sound_world->update();
+
+	process_physics_events();
 }
 
 //-----------------------------------------------------------------------------
@@ -294,4 +298,70 @@ SoundWorld* World::sound_world()
 	return m_sound_world;
 }
 
+//-----------------------------------------------------------------------------
+void World::process_physics_events()
+{
+	EventStream& events = m_physics_world.events();
+
+	// Read all events
+	const char* ee = array::begin(events);
+	while (ee != array::end(events))
+	{
+		event_stream::Header h = *(event_stream::Header*) ee;
+
+		// Log::d("=== PHYSICS EVENT ===");
+		// Log::d("type = %d", h.type);
+		// Log::d("size = %d", h.size);
+
+		const char* event = ee + sizeof(event_stream::Header);
+
+		switch (h.type)
+		{
+			case physics_world::EventType::COLLISION:
+			{
+				physics_world::CollisionEvent coll_ev = *(physics_world::CollisionEvent*) event;
+
+				// Log::d("type    = %s", coll_ev.type == physics_world::CollisionEvent::BEGIN_TOUCH ? "begin" : "end");
+				// Log::d("actor_0 = (%p)", coll_ev.actors[0]);
+				// Log::d("actor_1 = (%p)", coll_ev.actors[1]);
+				// Log::d("unit_0  = (%p)", coll_ev.actors[0]->unit());
+				// Log::d("unit_1  = (%p)", coll_ev.actors[1]->unit());
+				// Log::d("where   = (%f %f %f)", coll_ev.where.x, coll_ev.where.y, coll_ev.where.z);
+				// Log::d("normal  = (%f %f %f)", coll_ev.normal.x, coll_ev.normal.y, coll_ev.normal.z);
+
+				device()->lua_environment()->call_physics_callback(
+					coll_ev.actors[0],
+					coll_ev.actors[1],
+					coll_ev.actors[0]->unit(),
+					coll_ev.actors[1]->unit(),
+					coll_ev.where,
+					coll_ev.normal,
+					(coll_ev.type == physics_world::CollisionEvent::BEGIN_TOUCH) ? "begin" : "end");
+				break;
+			}
+			case physics_world::EventType::TRIGGER:
+			{
+				physics_world::TriggerEvent trigg_ev = *(physics_world::TriggerEvent*) event;
+
+				// Log::d("type    = %s", trigg_ev.type == physics_world::TriggerEvent::BEGIN_TOUCH ? "begin" : "end");
+				// Log::d("trigger = (%p)", trigg_ev.trigger);
+				// Log::d("other   = (%p)", trigg_ev.other);
+				break;
+			}
+			default:
+			{
+				CE_FATAL("Unknown Physics event");
+				break;
+			}
+		}
+
+		// Log::d("=====================");
+
+		// Next event
+		ee += sizeof(event_stream::Header) + h.size;
+	}
+
+	array::clear(events);
+}
+
 } // namespace crown

+ 39 - 34
engine/world/World.h

@@ -61,77 +61,82 @@ struct DebugLine;
 class World
 {
 public:
-										World();
-										~World();
+	
+	World();
+	~World();
 
-	WorldId								id() const;
-	void								set_id(WorldId id);
+	WorldId id() const;
+	void set_id(WorldId id);
 
 	/// Spawns a new instance of the unit @a name at the given @a position and @a rotation.
-	UnitId								spawn_unit(const char* name, const Vector3& position = vector3::ZERO, const Quaternion& rotation = quaternion::IDENTITY);
-	UnitId								spawn_unit(const ResourceId id, UnitResource* ur, const Vector3& pos, const Quaternion& rot);
+	UnitId spawn_unit(const char* name, const Vector3& position = vector3::ZERO, const Quaternion& rotation = quaternion::IDENTITY);
+	UnitId spawn_unit(const ResourceId id, UnitResource* ur, const Vector3& pos, const Quaternion& rot);
 
 	/// Destroys the unit with the given @a id.
-	void								destroy_unit(UnitId id);
-	void								reload_units(UnitResource* old_ur, UnitResource* new_ur);
+	void destroy_unit(UnitId id);
+	void reload_units(UnitResource* old_ur, UnitResource* new_ur);
 
 	/// Returns the number of units in the world.
-	uint32_t							num_units() const;
+	uint32_t num_units() const;
 
 	/// Links the unit @a child to the @a node of the unit @a parent.
 	/// After this call, @a child will follow the @a parent unit.
-	void								link_unit(UnitId child, UnitId parent, int32_t node);
+	void link_unit(UnitId child, UnitId parent, int32_t node);
 
 	/// Unlinks the unit @a unit from its parent if it has any.
-	void								unlink_unit(UnitId unit);
+	void unlink_unit(UnitId unit);
 
-	Unit*								lookup_unit(UnitId unit);
-	Camera*								lookup_camera(CameraId camera);
+	Unit* lookup_unit(UnitId unit);
+	Camera* lookup_camera(CameraId camera);
 
 	/// Updates all units and sub-systems with the given @a dt delta time.
-	void								update(float dt);
+	void update(float dt);
 
 	/// Renders the world form the point of view of the given @a camera.
-	void								render(Camera* camera);
+	void render(Camera* camera);
 
-	CameraId							create_camera(SceneGraph& sg, int32_t node);
-	void								destroy_camera(CameraId id);
+	CameraId create_camera(SceneGraph& sg, int32_t node);
+	void destroy_camera(CameraId id);
 
 	/// Plays the sound with the given @æ name at the given @a position, with the given
 	/// @a volume and @a range. @a loop controls whether the sound must loop or not.
-	SoundInstanceId						play_sound(const char* name, bool loop = false, float volume = 1.0f, const Vector3& position = vector3::ZERO, float range = 50.0f);
+	SoundInstanceId play_sound(const char* name, bool loop = false, float volume = 1.0f, const Vector3& position = vector3::ZERO, float range = 50.0f);
 
 	/// Stops the sound with the given @a id.
-	void								stop_sound(SoundInstanceId id);
+	void stop_sound(SoundInstanceId id);
 
 	/// Links the sound @a if to the @a node of the given @æ unit.
 	/// After this call, the sound @a id will follow the unit @æ unit.
-	void								link_sound(SoundInstanceId id, Unit* unit, int32_t node);
+	void link_sound(SoundInstanceId id, Unit* unit, int32_t node);
 
 	/// Sets the @a pose of the listener.
-	void								set_listener_pose(const Matrix4x4& pose);
+	void set_listener_pose(const Matrix4x4& pose);
 
 	/// Sets the @a position of the sound @a id.
-	void								set_sound_position(SoundInstanceId id, const Vector3& position);
+	void set_sound_position(SoundInstanceId id, const Vector3& position);
 
 	/// Sets the @a range of the sound @a id.
-	void								set_sound_range(SoundInstanceId id, float range);
+	void set_sound_range(SoundInstanceId id, float range);
 
 	/// Sets the @a volume of the sound @a id.
-	void								set_sound_volume(SoundInstanceId id, float volume);
+	void set_sound_volume(SoundInstanceId id, float volume);
 
-	GuiId								create_window_gui(const char* name);
-	GuiId								create_world_gui(const Matrix4x4 pose, const uint32_t width, const uint32_t height);
-	void								destroy_gui(GuiId id);
-	Gui*								lookup_gui(GuiId id);
+	GuiId create_window_gui(const char* name);
+	GuiId create_world_gui(const Matrix4x4 pose, const uint32_t width, const uint32_t height);
+	void destroy_gui(GuiId id);
+	Gui* lookup_gui(GuiId id);
 
-	DebugLine*							create_debug_line(bool depth_test);
-	void								destroy_debug_line(DebugLine* line);
+	DebugLine* create_debug_line(bool depth_test);
+	void destroy_debug_line(DebugLine* line);
 
-	SceneGraphManager*					scene_graph_manager();
-	RenderWorld*						render_world();
-	PhysicsWorld*						physics_world();
-	SoundWorld*							sound_world();
+	SceneGraphManager* scene_graph_manager();
+	RenderWorld* render_world();
+	PhysicsWorld* physics_world();
+	SoundWorld* sound_world();
+
+private:
+
+	void process_physics_events();
 
 private: