diff --git a/src/lol/algorithm/aabb_tree.h b/src/lol/algorithm/aabb_tree.h
new file mode 100644
index 00000000..ee2f7de9
--- /dev/null
+++ b/src/lol/algorithm/aabb_tree.h
@@ -0,0 +1,359 @@
+//
+// Lol Engine
+//
+// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
+//            (c) 2013-2014 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of the Do What The Fuck You Want To
+//   Public License, Version 2, as published by Sam Hocevar. See
+//   http://www.wtfpl.net/ for more details.
+//
+
+#if !defined __LOL_SPACE_PARTITIONING_H__
+#define __LOL_SPACE_PARTITIONING_H__
+
+#include <lol/base/array.h>
+
+namespace lol
+{
+
+//------ AABB TREE SYSTEM -----
+template <typename TE, typename TV, typename TB, size_t child_nb>
+class AABBTree
+{
+    struct NodeLeaf
+    {
+        int             m_parent;
+        //Children pos in the list
+        int             m_children[child_nb];
+        //Element list
+        Array<int>      m_elements;
+
+        NodeLeaf(int parent)
+        {
+            m_parent = parent;
+            for (int i = 0; i < child_nb; i++)
+                m_children[i] = 0;
+        }
+    };
+
+    struct TreeElement
+    {
+        TE*             m_element;
+        Array<int>      m_leaves;
+
+        inline bool operator==(const TE*& element) { return m_element == element; }
+    };
+
+public:
+    AABBTree()
+    {
+        m_max_depth = 1;
+        m_max_element = 1;
+        AddLeaf(0);
+    }
+    ~AABBTree()
+    {
+    }
+
+private:
+    //--
+    bool                CleanupEmptyLeaves(int leaf=0)
+    {
+        int empty_children = 0;
+        for (int i = 0; i < child_nb; i++)
+        {
+            bool child_empty = false;
+            if (m_tree[leaf].m_children[i] != 0)
+                child_empty = CleanupEmptyLeaves(m_tree[leaf].m_children[i]);
+            empty_children += (int)(m_tree[leaf].m_children[i] == 0 || child_empty);
+        }
+        if (empty_children == 4 && leaf != 0)
+        {
+            for (int i = 0; i < child_nb; i++)
+            {
+                int old_leaf = m_tree[leaf].m_children[i];
+                if (old_leaf != 0)
+                    m_free_leaves << old_leaf;
+                m_tree[leaf].m_children[i] = 0;
+            }
+            return true;
+        }
+        return false;
+    }
+    //--
+    void                RemoveElement(TE* element)
+    {
+        int idx = INDEX_NONE;
+        for (int i = 0; i < m_elements.Count(); ++i)
+            if (m_elements[i].m_element == element)
+                idx = i;
+
+        if (idx == INDEX_NONE)
+            return;
+
+        //Remove item from tree leaves
+        for (int i = 0; i < m_elements[idx].m_leaves.Count(); i++)
+            m_tree[m_elements[idx].m_leaves[i]].m_elements.RemoveItem(idx);
+
+        //Try leaves cleanup
+        CleanupEmptyLeaves();
+    }
+    //--
+    int                 AddElement(TE* element)
+    {
+        for (int i = 0; i < m_elements.Count(); ++i)
+            if (m_elements[i].m_element == element)
+                return i;
+
+        TreeElement new_element;
+        new_element.m_element = element;
+        new_element.m_leaves = Array<int>();
+        m_elements << new_element;
+        return m_elements.Count() - 1;
+    }
+    //--
+    int                 AddLeaf(int parent)
+    {
+        int idx = m_tree.Count();
+        if (m_free_leaves.Count())
+        {
+            idx = m_free_leaves.Pop();
+            m_tree[idx] = NodeLeaf(parent);
+        }
+        else
+            m_tree << NodeLeaf(parent);
+        return idx;
+    }
+
+    //--
+    virtual TV          GetSubOffset(int sub) = 0;
+    virtual TB          GetAABB() { return TB(-m_size * .5f, m_size * .5f); }
+    virtual TB          GetSubAABB(const TB& bbox, int sub)
+    {
+        TV v(GetSubOffset(sub));
+        TV half_vec = (bbox.B - bbox.A) * .5f;
+        return TB(bbox.A + half_vec * v,
+                  bbox.A + half_vec * (v + TV::one));
+    }
+    //--
+    bool                TestLeaf(int leaf, const TB& leaf_bb, const TB& test_bb, Array<TE*>& elements)
+    {
+        bool result = false;
+        if (TestAABBVsAABB(leaf_bb, test_bb))
+        {
+            NodeLeaf& node = m_tree[leaf];
+            for (int i = 0; i < child_nb; i++)
+            {
+                if (node.m_children[i] != 0)
+                {
+                    TB sub_aabb = GetSubAABB(leaf_bb, i);
+                    result = result | TestLeaf(node.m_children[i], sub_aabb, test_bb, elements);
+                }
+                else
+                {
+                    for (int j = 0; j < node.m_elements.Count(); j++)
+                        elements.PushUnique(m_elements[node.m_elements[j]].m_element);
+                    result = true;
+                }
+            }
+        }
+        return result;
+    }
+    //--
+    bool                RegisterElement(TE* element, int leaf, TB leaf_bb, int depth)
+    {
+        if (TestAABBVsAABB(leaf_bb, element->GetAABB()))
+        {
+            bool found_child = false;
+            for (int i = 0; i < child_nb; i++)
+            {
+                TB child_bb = GetSubAABB(leaf_bb, i);
+                int child_leaf = m_tree[leaf].m_children[i];
+                //there is a child, go further down
+                if (child_leaf != 0)
+                    found_child = found_child | RegisterElement(element, child_leaf, child_bb, depth + 1);
+            }
+            if (found_child)
+                return true;
+
+            //Too much elements, we need to re-dispatch the elements
+            if (m_tree[leaf].m_elements.Count() + 1 > m_max_element &&
+                depth < m_max_depth)
+            {
+                //Extract elements
+                Array<int> elements = m_tree[leaf].m_elements;
+                elements.PushUnique(AddElement(element));
+                m_tree[leaf].m_elements.Empty();
+                //Add children
+                for (int j = 0; j < child_nb; j++)
+                    m_tree[leaf].m_children[j] = AddLeaf(leaf);
+                //Re-run extracted elements
+                while (elements.Count())
+                {
+                    RegisterElement(m_elements[elements[0]].m_element, leaf, leaf_bb, depth);
+                    elements.Remove(0);
+                }
+            }
+            //else add to list.
+            else
+            {
+                int idx = AddElement(element);
+                m_elements[idx].m_leaves.PushUnique(leaf);
+                m_tree[leaf].m_elements.PushUnique(idx);
+            }
+            return true;
+        }
+        return false;
+    }
+
+public:
+    void                RegisterElement(TE* element)                        { RegisterElement(element, 0, GetAABB(), 0); }
+    void                UnregisterElement(TE* element)                      { RemoveElement(element); }
+    bool                FindElements(const TB& bbox, Array<TE*>& elements)  { return TestLeaf(0, GetAABB(), bbox, elements); }
+    void                Clear()
+    {
+        m_tree.Empty();
+        m_elements.Empty();
+    }
+
+    void                SetSize(TV size)            { m_size = size; }
+    void                SetMaxDepth(int max_depth)  { m_max_depth = max_depth; }
+
+#if LOL_BUILD_DEBUG
+    //DEBUG DRAW
+    virtual void        DebugDraw(vec4 color)
+    {
+        Array<int, TB> leaves;
+        Array<TB, vec4> boxes;
+        Array<TE*, int, vec4> elements;
+        boxes.Push(GetAABB(), vec4::one);
+        leaves.Push(0, boxes.Last().m1);
+        while (leaves.Count() > 0)
+        {
+            for (int j = 0; j < m_tree[leaves[0].m1].m_elements.Count(); j++)
+            {
+                bool done = false;
+                for (int k = 0; k < elements.Count(); k++)
+                {
+                    if (elements[k].m1 == m_elements[m_tree[leaves[0].m1].m_elements[j]].m_element)
+                    {
+                        elements[k].m2++;
+                        done = true;
+                        break;
+                    }
+                }
+                if (!done)
+                    elements.Push(m_elements[m_tree[leaves[0].m1].m_elements[j]].m_element, 1, vec4::v1001);
+            }
+
+            for (int i = 0; i < child_nb; i++)
+            {
+                if (m_tree[leaves[0].m1].m_children[i] != 0)
+                {
+                    TB bbox = GetSubAABB(leaves[0].m2, i);
+                    leaves.Push(m_tree[leaves[0].m1].m_children[i], bbox);
+                    boxes.Push(bbox, color);
+                }
+            }
+            leaves.Remove(0);
+        }
+        DebugDrawBoxes(boxes, elements);
+    }
+protected:
+    //DEBUG DRAW
+    virtual void        DebugDrawBoxes(Array<TB, vec4> boxes, Array<TE*, int, vec4> elements) = 0;
+#endif //LOL_BUILD_DEBUG
+
+protected:
+    Array<NodeLeaf>     m_tree;         //actual tree
+    Array<TreeElement>  m_elements;     //elements to leaves
+    Array<int>          m_free_leaves;  //leaves removed from tree
+    TV                  m_size;         //Main tree size
+    int                 m_max_depth;    //Maximum depth possible
+    int                 m_max_element;  //Maximum element per leaf
+};
+
+template <typename TE>
+class QuadTree : public AABBTree<TE, vec2, box2, 4>
+{
+public:
+    QuadTree()
+    {
+#if LOL_BUILD_DEBUG
+        m_debug_y_offset = 0;
+#endif //LOL_BUILD_DEBUG
+    }
+#if LOL_BUILD_DEBUG
+public:
+    float               m_debug_y_offset;
+protected:
+    virtual void        DebugDrawBoxes(Array<box2, vec4> boxes, Array<TE*, int, vec4> elements)
+    {
+        vec3 off = vec3::v010 * .1f;
+        vec3 add = vec3::v010 * .1f;
+        while (boxes.Count() > 0)
+        {
+            Debug::DrawBox(vec3(boxes[0].m1.A.x, m_debug_y_offset, boxes[0].m1.A.y),
+                           vec3(boxes[0].m1.B.x, m_debug_y_offset, boxes[0].m1.B.y),
+                           boxes[0].m2);
+            boxes.Remove(0);
+        }
+        while (elements.Count() > 0)
+        {
+            while (elements[0].m2 > 0)
+            {
+                Debug::DrawBox(vec3(elements[0].m1->GetAABB().A.x, m_debug_y_offset, elements[0].m1->GetAABB().A.y) + off * (float)elements[0].m2,
+                               vec3(elements[0].m1->GetAABB().B.x, m_debug_y_offset, elements[0].m1->GetAABB().B.y) + off * (float)elements[0].m2,
+                               elements[0].m3);
+                elements[0].m2--;
+            }
+            elements.Remove(0);
+        }
+    }
+#endif //LOL_BUILD_DEBUG
+protected:
+    virtual vec2        GetSubOffset(int sub) { return vec2(ivec2(sub % 2, sub / 2)); }
+};
+
+template <typename TE>
+class OcTree : public AABBTree<TE, vec3, box3, 8>
+{
+public:
+    virtual ~OcTree() {}
+
+protected:
+#if LOL_BUILD_DEBUG
+    virtual void DebugDrawBoxes(Array<box3, vec4> boxes, Array<TE*, int, vec4> elements)
+    {
+        vec3 off = vec3::v010 * .1f;
+        vec3 add = vec3::v010 * .1f;
+        while (boxes.Count() > 0)
+        {
+            float size = boxes[0].m1.B.x - boxes[0].m1.A.x;
+            Debug::DrawBox(vec3(boxes[0].m1.A.x, boxes[0].m1.A.y, boxes[0].m1.A.z) /* + off * (m_size.x / size) */,
+                           vec3(boxes[0].m1.B.x, boxes[0].m1.B.y, boxes[0].m1.B.z) /* + off * (m_size.x / size) */,
+                           boxes[0].m2);
+            //off += add;
+            boxes.Remove(0);
+        }
+        while (elements.Count() > 0)
+        {
+            while (elements[0].m2 > 0)
+            {
+                Debug::DrawBox(vec3(elements[0].m1->GetAABB().A.x, elements[0].m1->GetAABB().A.y, elements[0].m1->GetAABB().A.z) + off * (float)elements[0].m2,
+                               vec3(elements[0].m1->GetAABB().B.x, elements[0].m1->GetAABB().B.y, elements[0].m1->GetAABB().B.z) + off * (float)elements[0].m2,
+                               elements[0].m3);
+                elements[0].m2--;
+            }
+            elements.Remove(0);
+        }
+    }
+#endif //LOL_BUILD_DEBUG
+    virtual vec3        GetSubOffset(int sub) { return vec3(ivec3(sub % 2, sub / 4, (sub % 4) / 2)); }
+};
+
+} /* namespace lol */
+
+#endif // __LOL_SPACE_PARTITIONING_H__
+
diff --git a/src/lol/algorithm/all.h b/src/lol/algorithm/all.h
index a47b6395..5b9ab9f3 100644
--- a/src/lol/algorithm/all.h
+++ b/src/lol/algorithm/all.h
@@ -12,6 +12,7 @@
 #define __LOL_ALGORITHM_ALL_H__
 
 #include <lol/algorithm/sort.h>
+#include <lol/algorithm/aabb_tree.h>
 
 #endif // __LOL_ALGORITHM_ALL_H__
 
diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj
index 1d17f1d9..035b9d26 100644
--- a/src/lolcore.vcxproj
+++ b/src/lolcore.vcxproj
@@ -269,6 +269,7 @@
     <ClInclude Include="light.h" />
     <ClInclude Include="loldebug.h" />
     <ClInclude Include="lolgl.h" />
+    <ClInclude Include="lol\algorithm\aabb_tree.h" />
     <ClInclude Include="lol\algorithm\all.h" />
     <ClInclude Include="lol\algorithm\sort.h" />
     <ClInclude Include="lol\base\all.h" />
@@ -422,4 +423,4 @@
   <ImportGroup Label="ExtensionTargets">
     <Import Project="$(SolutionDir)\Lol.Fx.targets" />
   </ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters
index ca071cf6..dcb00783 100644
--- a/src/lolcore.vcxproj.filters
+++ b/src/lolcore.vcxproj.filters
@@ -676,6 +676,9 @@
     <ClInclude Include="easymesh\easymeshbuild.h">
       <Filter>easymesh</Filter>
     </ClInclude>
+    <ClInclude Include="lol\algorithm\aabb_tree.h">
+      <Filter>lol\algorithm</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <LolFxCompile Include="gpu\emptymaterial.lolfx">
@@ -733,4 +736,4 @@
     </None>
     <None Include="Makefile.am" />
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file