| @@ -42,7 +42,7 @@ liblolcore_headers = \ | |||||
| lol/math/constants.h \ | lol/math/constants.h \ | ||||
| \ | \ | ||||
| lol/algorithm/all.h \ | lol/algorithm/all.h \ | ||||
| lol/algorithm/sort.h \ | |||||
| lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \ | |||||
| \ | \ | ||||
| lol/sys/all.h \ | lol/sys/all.h \ | ||||
| lol/sys/init.h lol/sys/file.h lol/sys/thread.h lol/sys/atomic.h \ | lol/sys/init.h lol/sys/file.h lol/sys/thread.h lol/sys/atomic.h \ | ||||
| @@ -9,8 +9,8 @@ | |||||
| // http://www.wtfpl.net/ for more details. | // http://www.wtfpl.net/ for more details. | ||||
| // | // | ||||
| #if !defined __LOL_SPACE_PARTITIONING_H__ | |||||
| #define __LOL_SPACE_PARTITIONING_H__ | |||||
| #if !defined __LOL_AABB_TREE_H__ | |||||
| #define __LOL_AABB_TREE_H__ | |||||
| #include <lol/base/array.h> | #include <lol/base/array.h> | ||||
| #include <lol/debug/lines.h> | #include <lol/debug/lines.h> | ||||
| @@ -19,6 +19,114 @@ namespace lol | |||||
| { | { | ||||
| //------ AABB TREE SYSTEM ----- | //------ AABB TREE SYSTEM ----- | ||||
| template <typename TE, typename TV, typename TB, size_t child_nb> class AABBTree; | |||||
| template <typename TE> class QuadTree; | |||||
| template <typename TE> class OcTree; | |||||
| //-- | |||||
| namespace Debug { | |||||
| //-- | |||||
| #define GET_DRAW_DATA(DEF_TREE, DEF_BOXES, DEF_ELEM, CHILD_NB, TBB) \ | |||||
| boxes.Push(tree->GetAABB(), vec4::one); \ | |||||
| leaves.Push(0, boxes.Last().m1); \ | |||||
| while (leaves.Count() > 0) \ | |||||
| { \ | |||||
| for (int j = 0; j < tree->m_tree[leaves[0].m1].m_elements.Count(); j++) \ | |||||
| { \ | |||||
| bool done = false; \ | |||||
| for (int k = 0; k < elements.Count(); k++) \ | |||||
| { \ | |||||
| if (elements[k].m1 == tree->m_elements[tree->m_tree[leaves[0].m1].m_elements[j]].m_element) \ | |||||
| { \ | |||||
| elements[k].m2++; \ | |||||
| done = true; \ | |||||
| break; \ | |||||
| } \ | |||||
| } \ | |||||
| if (!done) \ | |||||
| elements.Push(tree->m_elements[tree->m_tree[leaves[0].m1].m_elements[j]].m_element, 1, vec4::v1001); \ | |||||
| } \ | |||||
| \ | |||||
| for (int i = 0; i < CHILD_NB; i++) \ | |||||
| { \ | |||||
| if (tree->m_tree[leaves[0].m1].m_children[i] != 0) \ | |||||
| { \ | |||||
| TBB bbox = tree->GetSubAABB(leaves[0].m2, i); \ | |||||
| leaves.Push(tree->m_tree[leaves[0].m1].m_children[i], bbox); \ | |||||
| boxes.Push(bbox, color); \ | |||||
| } \ | |||||
| } \ | |||||
| leaves.Remove(0); \ | |||||
| } | |||||
| //-- | |||||
| template <typename TE> | |||||
| void Draw(QuadTree<TE>* tree, vec4 color) | |||||
| { | |||||
| Array<box2, vec4> boxes; | |||||
| Array<TE*, int, vec4> elements; | |||||
| Array<int, box2> leaves; | |||||
| GET_DRAW_DATA(tree, boxes, elements, 4, box2); | |||||
| vec3 off = vec3::v010 * .1f; | |||||
| vec3 add = vec3::v010 * .1f; | |||||
| while (boxes.Count() > 0) | |||||
| { | |||||
| Debug::DrawBox(vec3(boxes[0].m1.A.x, tree->m_debug_y_offset, boxes[0].m1.A.y), | |||||
| vec3(boxes[0].m1.B.x, tree->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, tree->m_debug_y_offset, elements[0].m1->GetAABB().A.y) + off * (float)elements[0].m2, | |||||
| vec3(elements[0].m1->GetAABB().B.x, tree->m_debug_y_offset, elements[0].m1->GetAABB().B.y) + off * (float)elements[0].m2, | |||||
| elements[0].m3); | |||||
| elements[0].m2--; | |||||
| } | |||||
| elements.Remove(0); | |||||
| } | |||||
| } | |||||
| //-- | |||||
| template <typename TE> | |||||
| void Draw(OcTree<TE>* tree, vec4 color) | |||||
| { | |||||
| Array<vec3, vec4> boxes; | |||||
| Array<TE*, int, vec4> elements; | |||||
| Array<int, box3> leaves; | |||||
| GET_DRAW_DATA(tree, boxes, elements, 8, box3); | |||||
| 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); | |||||
| } | |||||
| } | |||||
| //-- | |||||
| } | |||||
| //-- | |||||
| template <typename TE, typename TV, typename TB, size_t child_nb> | template <typename TE, typename TV, typename TB, size_t child_nb> | ||||
| class AABBTree | class AABBTree | ||||
| { | { | ||||
| @@ -53,9 +161,7 @@ public: | |||||
| m_max_element = 1; | m_max_element = 1; | ||||
| AddLeaf(0); | AddLeaf(0); | ||||
| } | } | ||||
| ~AABBTree() | |||||
| { | |||||
| } | |||||
| ~AABBTree() { } | |||||
| private: | private: | ||||
| //-- | //-- | ||||
| @@ -127,16 +233,6 @@ private: | |||||
| return idx; | 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 TestLeaf(int leaf, const TB& leaf_bb, const TB& test_bb, Array<TE*>& elements) | ||||
| { | { | ||||
| @@ -218,53 +314,20 @@ public: | |||||
| m_elements.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) | |||||
| //-- | |||||
| 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) | |||||
| { | { | ||||
| 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); | |||||
| 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)); | |||||
| } | } | ||||
| protected: | |||||
| //DEBUG DRAW | |||||
| virtual void DebugDrawBoxes(Array<TB, vec4> boxes, Array<TE*, int, vec4> elements) = 0; | |||||
| #endif //LOL_BUILD_DEBUG | |||||
| //-- | |||||
| void SetSize(TV size) { m_size = size; } | |||||
| void SetMaxDepth(int max_depth) { m_max_depth = max_depth; } | |||||
| protected: | protected: | ||||
| Array<NodeLeaf> m_tree; //actual tree | Array<NodeLeaf> m_tree; //actual tree | ||||
| @@ -275,86 +338,32 @@ protected: | |||||
| int m_max_element; //Maximum element per leaf | int m_max_element; //Maximum element per leaf | ||||
| }; | }; | ||||
| //-- | |||||
| template <typename TE> | template <typename TE> | ||||
| class QuadTree : public AABBTree<TE, vec2, box2, 4> | class QuadTree : public AABBTree<TE, vec2, box2, 4> | ||||
| { | { | ||||
| template <typename TE> friend void Debug::Draw(QuadTree<TE>* tree, vec4 color); | |||||
| public: | public: | ||||
| QuadTree() | |||||
| { | |||||
| #if LOL_BUILD_DEBUG | |||||
| m_debug_y_offset = 0; | |||||
| #endif //LOL_BUILD_DEBUG | |||||
| } | |||||
| #if LOL_BUILD_DEBUG | |||||
| public: | |||||
| QuadTree() { m_debug_y_offset = 0.f; } | |||||
| virtual ~QuadTree() { } | |||||
| float m_debug_y_offset; | 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: | protected: | ||||
| virtual vec2 GetSubOffset(int sub) { return vec2(ivec2(sub % 2, sub / 2)); } | virtual vec2 GetSubOffset(int sub) { return vec2(ivec2(sub % 2, sub / 2)); } | ||||
| }; | }; | ||||
| //-- | |||||
| template <typename TE> | template <typename TE> | ||||
| class OcTree : public AABBTree<TE, vec3, box3, 8> | class OcTree : public AABBTree<TE, vec3, box3, 8> | ||||
| { | { | ||||
| template <typename TE> friend void Debug::Draw(OcTree<TE>* tree, vec4 color); | |||||
| public: | public: | ||||
| virtual ~OcTree() {} | |||||
| OcTree() { } | |||||
| virtual ~OcTree() { } | |||||
| protected: | 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)); } | virtual vec3 GetSubOffset(int sub) { return vec3(ivec3(sub % 2, sub / 4, (sub % 4) / 2)); } | ||||
| }; | }; | ||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| #endif // __LOL_SPACE_PARTITIONING_H__ | |||||
| #endif // __LOL_AABB_TREE_H__ | |||||
| @@ -13,6 +13,7 @@ | |||||
| #include <lol/algorithm/sort.h> | #include <lol/algorithm/sort.h> | ||||
| #include <lol/algorithm/aabb_tree.h> | #include <lol/algorithm/aabb_tree.h> | ||||
| #include <lol/algorithm/portal.h> | |||||
| #endif // __LOL_ALGORITHM_ALL_H__ | #endif // __LOL_ALGORITHM_ALL_H__ | ||||
| @@ -0,0 +1,391 @@ | |||||
| // | |||||
| // 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_PORTAL_H__ | |||||
| #define __LOL_PORTAL_H__ | |||||
| #include <lol/base/array.h> | |||||
| #include <lol/debug/lines.h> | |||||
| namespace lol | |||||
| { | |||||
| //------ PORTAL SYSTEM -------- | |||||
| template <typename TE> class PortalRoom; | |||||
| template <typename TE> class PortalDoor; | |||||
| template <typename TE> class PortalSet; | |||||
| //-- | |||||
| namespace Debug { | |||||
| template <typename TE> | |||||
| void Draw(PortalDoor<TE>& port, vec4 color) | |||||
| { | |||||
| vec3 points[4]; port.GetPoints(points); | |||||
| //Draw normal | |||||
| vec3 p = port.m_center + port.m_up * port.m_size.y * .5f; | |||||
| Debug::DrawLine(p, p + port.m_normal, vec4::v1001); | |||||
| Debug::DrawLine(p, p + port.m_up, vec4::v0101); | |||||
| //draw door | |||||
| for (int l = 0; l < 4; l++) | |||||
| Debug::DrawLine(points[l], points[(l + 1) % 4], color); | |||||
| Debug::DrawLine(points[0], points[2], color); | |||||
| Debug::DrawLine(points[1], points[3], color); | |||||
| } | |||||
| } | |||||
| //PortalDoor base class | |||||
| template <typename TE> | |||||
| class PortalDoor | |||||
| { | |||||
| template<typename TE> friend class PortalSet; | |||||
| template<typename TE> friend class PortalRoom; | |||||
| template<typename TE> friend void Debug::Draw(PortalDoor<TE>& port, vec4 color); | |||||
| private: | |||||
| void Init() | |||||
| { | |||||
| m_center = vec3::zero; | |||||
| m_normal = vec3::zero; | |||||
| m_up = vec3::zero; | |||||
| m_size = vec2::zero; | |||||
| m_view = mat4::identity; | |||||
| m_proj = mat4::identity; | |||||
| m_rooms[0] = nullptr; | |||||
| m_rooms[1] = nullptr; | |||||
| } | |||||
| public: | |||||
| //Normal portal | |||||
| PortalDoor(vec3 center, vec3 normal, vec3 up, vec2 size) | |||||
| { | |||||
| Init(); | |||||
| m_center = center; | |||||
| m_normal = normal; | |||||
| m_up = up; | |||||
| m_size = size; | |||||
| } | |||||
| //Camera portal | |||||
| PortalDoor(mat4 view, mat4 proj) | |||||
| { | |||||
| Init(); | |||||
| m_view = view; | |||||
| m_proj = proj; | |||||
| } | |||||
| //D.Tor | |||||
| ~PortalDoor() | |||||
| { | |||||
| ConnectRooms(nullptr, nullptr); | |||||
| } | |||||
| //Connect door to room | |||||
| void ConnectRooms(class PortalRoom<TE>* front_room, class PortalRoom<TE>* back_room) | |||||
| { | |||||
| for (int i = 0; i < 2; i++) | |||||
| if (m_rooms[i] != nullptr) | |||||
| *m_rooms[i] >> this; | |||||
| m_rooms[0] = back_room; | |||||
| m_rooms[1] = front_room; | |||||
| for (int i = 0; i < 2; i++) | |||||
| if (m_rooms[i] != nullptr) | |||||
| *m_rooms[i] << this; | |||||
| } | |||||
| //-- | |||||
| void DisconnectRoom(class PortalRoom<TE>* room) | |||||
| { | |||||
| for (int i = 0; i < 2; i++) | |||||
| if (m_rooms[i] != nullptr && m_rooms[i] == room) | |||||
| m_rooms[i] = nullptr; | |||||
| } | |||||
| //-- | |||||
| PortalRoom<TE>* GetRoom(bool front) { return m_rooms[(int)front]; } | |||||
| PortalRoom<TE>* GetRoom(PortalRoom<TE>* room) { return (m_rooms[0] == room) ? m_rooms[1] : m_rooms[0]; } | |||||
| //Get Four portal point | |||||
| void GetPoints(vec3 *points) const | |||||
| { | |||||
| vec3 right = cross(m_normal, m_up); | |||||
| points[0] = m_center + right * m_size.x * .5f + m_up * m_size.y; | |||||
| points[1] = m_center + right * m_size.x * .5f; | |||||
| points[2] = m_center + right * m_size.x * -.5f; | |||||
| points[3] = m_center + right * m_size.x * -.5f + m_up * m_size.y; | |||||
| } | |||||
| //Builds the portal view proj. | |||||
| //Returns false if portal is out of the view or points are on each others. | |||||
| bool BuildViewProj(mat4 view, mat4 proj) | |||||
| { | |||||
| mat4 cam_mx = proj * view; | |||||
| mat4 inv_proj_mx = inverse(proj); | |||||
| //First: Check normal dot | |||||
| if (lol::abs(dot((inverse(view) * vec4::v0010).xyz, m_normal)) < .00001f) | |||||
| return false; | |||||
| //Second: convert in screen | |||||
| vec3 port_2d[2] = { vec3(FLT_MAX), vec3(-FLT_MAX) }; | |||||
| vec3 door_points[4]; | |||||
| vec4 proj_p[4]; | |||||
| GetPoints(door_points); | |||||
| for (int i = 0; i < 4; i++) | |||||
| { | |||||
| //W to S calculations | |||||
| proj_p[i] = cam_mx * vec4(door_points[i], 1.f); | |||||
| proj_p[i] /= proj_p[i].w; | |||||
| //Clamp points within screen | |||||
| port_2d[0] = lol::min(proj_p[i].xyz, port_2d[0]); | |||||
| port_2d[1] = lol::max(proj_p[i].xyz, port_2d[1]); | |||||
| port_2d[0] = vec3(lol::clamp(port_2d[0].xy, vec2::onen, vec2::one), port_2d[0].z); | |||||
| port_2d[1] = vec3(lol::clamp(port_2d[1].xy, vec2::onen, vec2::one), port_2d[1].z); | |||||
| } | |||||
| //Quit if door not within the screen | |||||
| for (int i = 0; i < 3; i++) | |||||
| if (port_2d[0][i] == port_2d[1][i]) | |||||
| return false; | |||||
| //Third: Convert back to view | |||||
| ivec2 j[4] = { ivec2::v00, ivec2::v01, ivec2::v11, ivec2::v10 }; | |||||
| vec3 frust[2] = { vec3::one * FLT_MAX, vec3::one * -FLT_MAX }; | |||||
| for (int i = 0; i < 5; i++) | |||||
| { | |||||
| int k = i % 4; | |||||
| //world calculations | |||||
| proj_p[k] = inv_proj_mx * vec4(port_2d[j[k].x].x, port_2d[j[k].y].y, (i<4)?(port_2d[0].z):(1.f), 1.f); | |||||
| proj_p[k] /= proj_p[k].w; | |||||
| proj_p[k].z = lol::abs(proj_p[k].z); | |||||
| for (int h = 0; h < 3; h++) | |||||
| { | |||||
| if (i < 4 || h > 1) | |||||
| { | |||||
| frust[0][h] = lol::min(frust[0][h], proj_p[k][h]); | |||||
| frust[1][h] = lol::max(frust[1][h], proj_p[k][h]); | |||||
| } | |||||
| } | |||||
| } | |||||
| //Fourth: Create frustum | |||||
| m_proj = mat4::frustum(frust[0].x, frust[1].x, frust[0].y, frust[1].y, frust[0].z, frust[1].z); | |||||
| m_view = view; | |||||
| return true; | |||||
| } | |||||
| //View proj getter (doesn't check matrix validity) | |||||
| mat4 GetViewProj() { return m_proj * m_view; } | |||||
| //-- | |||||
| bool TestCollide(const vec3& point) | |||||
| { | |||||
| return TestPointVsFrustum(point, GetViewProj()); | |||||
| } | |||||
| //-- | |||||
| bool TestCollide(const PortalDoor& door) | |||||
| { | |||||
| vec3 door_points[4]; | |||||
| vec3 res_points[4]; | |||||
| ivec3 pos_test = ivec3::zero; | |||||
| bool is_in = false; | |||||
| //Get points and test them on frustum | |||||
| door.GetPoints(door_points); | |||||
| for (int i = 0; i < 4; i++) | |||||
| { | |||||
| is_in = is_in || TestPointVsFrustum(door_points[i], GetViewProj(), &res_points[i]); | |||||
| if (is_in) | |||||
| return true; | |||||
| //Add points on test stuff | |||||
| pos_test += ivec3(lol::clamp(res_points[i], vec3::onen * 1.1f, vec3::one * 1.1f)); | |||||
| } | |||||
| return false; | |||||
| //Check if at least one point is not on the same side as the others | |||||
| for (int i = 0; i < 3; i++) | |||||
| if (lol::abs(pos_test[i]) == 4) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| mat4 m_view; | |||||
| mat4 m_proj; | |||||
| vec3 m_center; | |||||
| vec3 m_normal; | |||||
| vec3 m_up; | |||||
| vec2 m_size; | |||||
| PortalRoom<TE>* m_rooms[2]; //0: Back, 1: Front | |||||
| }; | |||||
| //-- | |||||
| template <typename TE> | |||||
| class PortalRoom | |||||
| { | |||||
| template<typename TE> friend class PortalSet; | |||||
| template<typename TE> friend class PortalDoor; | |||||
| public: | |||||
| PortalRoom(TE* element=nullptr) | |||||
| { | |||||
| m_element = element; | |||||
| } | |||||
| ~PortalRoom() | |||||
| { | |||||
| for (int i = 0; i < m_doors.Count(); i++) | |||||
| m_doors[i]->DisconnectRoom(this); | |||||
| m_doors.Empty(); | |||||
| } | |||||
| PortalRoom& operator<<(class PortalDoor<TE>* door) | |||||
| { | |||||
| m_doors.PushUnique(door); | |||||
| return *this; | |||||
| } | |||||
| PortalRoom& operator>>(class PortalDoor<TE>* door) | |||||
| { | |||||
| m_doors.RemoveSwapItem(door); | |||||
| return *this; | |||||
| } | |||||
| int GetDoorCount() { return m_doors.Count(); } | |||||
| PortalDoor<TE>* GetDoor(int i) { return m_doors[i]; } | |||||
| private: | |||||
| //Portals associated with this room. | |||||
| Array<PortalDoor<TE>*> m_doors; | |||||
| TE* m_element; | |||||
| }; | |||||
| //-- | |||||
| template <typename TE> | |||||
| class PortalSet | |||||
| { | |||||
| public: | |||||
| ~PortalSet() | |||||
| { | |||||
| for (int i = 0; i < m_doors.Count(); i++) | |||||
| delete m_doors[i]; | |||||
| for (int i = 0; i < m_rooms.Count(); i++) | |||||
| delete m_rooms[i]; | |||||
| m_doors.Empty(); | |||||
| m_rooms.Empty(); | |||||
| } | |||||
| //Visible room getter | |||||
| void GetVisibleRooms(PortalDoor<TE>* see_through, PortalRoom<TE>* start_room, Array<PortalRoom<TE>*>& visible_rooms) | |||||
| { | |||||
| Array<PortalDoor<TE>*> ignore_doors; | |||||
| GetVisibleRooms(see_through, start_room, visible_rooms, ignore_doors); | |||||
| #if LOL_BUILD_DEBUG | |||||
| for (int j = 0; j < visible_rooms.Count(); j++) | |||||
| { | |||||
| vec4 tmp = vec4::zero; | |||||
| for (int i = 0; i < visible_rooms[j]->m_doors.Count(); i++) | |||||
| { | |||||
| PortalDoor<TE>* port = visible_rooms[j]->m_doors[i]; | |||||
| Debug::Draw(*port, vec4::v0111); | |||||
| tmp += vec4(port->m_center, 1.f); | |||||
| } | |||||
| tmp /= tmp.w; | |||||
| Debug::DrawBox(tmp.xyz-vec3::one,tmp.xyz+vec3::one,vec4::v1101); | |||||
| } | |||||
| for (int i = 0; i < ignore_doors.Count(); i++) | |||||
| { | |||||
| PortalDoor<TE>* port = ignore_doors[i]; | |||||
| Debug::Draw(*port, vec4::v1011); | |||||
| Debug::DrawViewProj(port->m_view, port->m_proj, vec4::v1011); | |||||
| } | |||||
| #endif //LOL_BUILD_DEBUG | |||||
| } | |||||
| private: | |||||
| void GetVisibleRooms(PortalDoor<TE>* see_through, PortalRoom<TE>* start_room, Array<PortalRoom<TE>*>& visible_rooms, Array<PortalDoor<TE>*>& ignore_doors) | |||||
| { | |||||
| for (int i = 0; i < start_room->m_doors.Count(); i++) | |||||
| { | |||||
| PortalDoor<TE>* door = start_room->m_doors[i]; | |||||
| if (door == see_through || ignore_doors.Find(door) != INDEX_NONE) | |||||
| continue; | |||||
| if (see_through->TestCollide(*door)) | |||||
| { | |||||
| PortalRoom<TE>* other_room = door->GetRoom(start_room); | |||||
| if (visible_rooms.Find(other_room) != INDEX_NONE) | |||||
| continue; | |||||
| ignore_doors.PushUnique(door); | |||||
| visible_rooms.PushUnique(other_room); | |||||
| door->BuildViewProj(see_through->m_view, see_through->m_proj); | |||||
| GetVisibleRooms(door, other_room, visible_rooms, ignore_doors); | |||||
| } | |||||
| } | |||||
| } | |||||
| public: | |||||
| //Operator | |||||
| PortalSet<TE>& operator<<(class PortalRoom<TE>* room) | |||||
| { | |||||
| m_rooms.PushUnique(room); | |||||
| for (int i = 0; i < room->m_doors.Count(); i++) | |||||
| m_doors.PushUnique(room->m_doors[i]); | |||||
| return *this; | |||||
| } | |||||
| //-- | |||||
| PortalSet<TE>& operator>>(class PortalRoom<TE>* room) | |||||
| { | |||||
| for (int i = 0; i < room->m_doors.Count(); i++) | |||||
| *this >> room->m_doors[i]; | |||||
| m_rooms.RemoveItem(room); | |||||
| return *this; | |||||
| } | |||||
| //-- | |||||
| PortalSet<TE>& operator<<(class PortalDoor<TE>* door) | |||||
| { | |||||
| m_doors.PushUnique(door); | |||||
| return *this; | |||||
| } | |||||
| //-- | |||||
| PortalSet<TE>& operator>>(class PortalDoor<TE>* door) | |||||
| { | |||||
| m_doors.RemoveItem(door); | |||||
| return *this; | |||||
| } | |||||
| //-- | |||||
| int GetDoorCount() { return m_doors.Count(); } | |||||
| PortalDoor<TE>* GetDoor(int i) { return m_doors[i]; } | |||||
| int GetRoomCount() { return m_rooms.Count(); } | |||||
| PortalRoom<TE>* GetRoom(int i) { return m_rooms[i]; } | |||||
| private: | |||||
| //Portals associated with this room. | |||||
| Array<PortalRoom<TE>*> m_rooms; | |||||
| Array<PortalDoor<TE>*> m_doors; | |||||
| }; | |||||
| } /* namespace lol */ | |||||
| #endif // __LOL_PORTAL_H__ | |||||
| @@ -24,18 +24,6 @@ namespace lol | |||||
| namespace Debug | namespace Debug | ||||
| { | { | ||||
| //This funcs MUST be specialized | |||||
| template<typename T> | |||||
| void Draw(T& x, vec4 color) | |||||
| { | |||||
| ASSERT(0); | |||||
| } | |||||
| template<template <typename> class B, typename T> | |||||
| void Draw(B<T>* x, vec4 color) | |||||
| { | |||||
| x->DebugDraw(color); | |||||
| } | |||||
| void DrawLine(vec3 a, vec3 b, vec4 color); | void DrawLine(vec3 a, vec3 b, vec4 color); | ||||
| void DrawBox(box3 a, vec4 color); | void DrawBox(box3 a, vec4 color); | ||||
| void DrawBox(vec3 a, vec3 b, vec4 color); | void DrawBox(vec3 a, vec3 b, vec4 color); | ||||