diff --git a/bat/premake_vs2015.bat b/bat/premake_vs2015.bat index 3cbd07b..cf8a461 100644 --- a/bat/premake_vs2015.bat +++ b/bat/premake_vs2015.bat @@ -1,2 +1,2 @@ cd ..\ -premake5 solution \ No newline at end of file +premake5 solution_vs2015 \ No newline at end of file diff --git a/bat/premake_vs2017.bat b/bat/premake_vs2017.bat new file mode 100644 index 0000000..9ee4adb --- /dev/null +++ b/bat/premake_vs2017.bat @@ -0,0 +1,2 @@ +cd ..\ +premake5 solution_vs2017 \ No newline at end of file diff --git a/building.txt b/building.txt index dcdd949..8ead7da 100644 --- a/building.txt +++ b/building.txt @@ -10,6 +10,14 @@ Open build/vs2015/bounce.sln. Set testbed as the startup project. Press F5 to run. +Visual Studio 2017 + +Ensure you have installed the Visual Studio 2015 libraries +Say { premake5 vs2017 } on a command line. +Open build/vs2017/bounce.sln. +Set testbed as the startup project. +Press F5 to run. + Linux On a clean Ubuntu 16.04 install these packages first: diff --git a/doc/ignore.txt b/doc/ignore.txt deleted file mode 100644 index 0519ecb..0000000 --- a/doc/ignore.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/include/bounce/collision/trees/static_tree.h b/include/bounce/collision/trees/static_tree.h index 70fde14..d22e0f8 100644 --- a/include/bounce/collision/trees/static_tree.h +++ b/include/bounce/collision/trees/static_tree.h @@ -77,6 +77,9 @@ private : } }; + // + void Build(const b3AABB3* set, b3Node* node, u32* indices, u32 numObjects, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount); + // The nodes of this tree stored in an array. u32 m_nodeCount; b3Node* m_nodes; diff --git a/premake5.lua b/premake5.lua index d808df3..69733e1 100644 --- a/premake5.lua +++ b/premake5.lua @@ -226,7 +226,7 @@ if os.is "windows" then newaction { - trigger = "solution", + trigger = "solution_vs2015", description = "Generate solution", execute = function () os.execute ( "premake5 clean" ) @@ -234,6 +234,16 @@ if os.is "windows" then end } + newaction + { + trigger = "solution_vs2017", + description = "Generate solution", + execute = function () + os.execute ( "premake5 clean" ) + os.execute ( "premake5 vs2017" ) + end + } + newaction { trigger = "doc", diff --git a/src/bounce/collision/trees/static_tree.cpp b/src/bounce/collision/trees/static_tree.cpp index 647223a..d34f8f4 100644 --- a/src/bounce/collision/trees/static_tree.cpp +++ b/src/bounce/collision/trees/static_tree.cpp @@ -18,7 +18,6 @@ #include #include -#include b3StaticTree::b3StaticTree() { @@ -31,41 +30,129 @@ b3StaticTree::~b3StaticTree() b3Free(m_nodes); } -struct b3Params +static B3_FORCE_INLINE bool b3SortPredicate(const b3AABB3* set, u32 axis, u32 a, u32 b) { - u32 node; - u32* indices; - u32 numObjects; -}; + const b3AABB3* b1 = set + a; + const b3AABB3* b2 = set + b; -struct b3SortPredicate + b3Vec3 c1 = b1->Centroid(); + b3Vec3 c2 = b2->Centroid(); + + return c1[axis] < c2[axis]; +} + +static void b3Sort(const b3AABB3* set, u32 axis, u32* ids, u32 count) { - const b3AABB3* bs; - u32 axis; - - bool operator()(const u32& i, const u32& j) const + if (count <= 1) { - const b3AABB3* b1 = bs + i; - const b3AABB3* b2 = bs + j; - - b3Vec3 c1 = b1->Centroid(); - b3Vec3 c2 = b2->Centroid(); - - if (c1[axis] < c2[axis]) - { - return true; - } - - return false; + return; } -}; -void b3StaticTree::Build(const b3AABB3* set, u32 n) + u32 pivot = ids[count - 1]; + u32 low = 0; + for (u32 i = 0; i < count - 1; ++i) + { + if (b3SortPredicate(set, axis, ids[i], pivot)) + { + u32 tmp = ids[i]; + ids[i] = ids[low]; + ids[low] = tmp; + low++; + } + } + + ids[count - 1] = ids[low]; + ids[low] = pivot; + + b3Sort(set, axis, ids, low); + b3Sort(set, axis, ids + low + 1, count - 1 - low); +} + +static u32 b3Partition(const b3AABB3& setAABB, const b3AABB3* set, u32* ids, u32 count) { - B3_ASSERT(n > 0); + u32 splitAxis = setAABB.GetLongestAxisIndex(); + float32 splitPos = setAABB.Centroid()[splitAxis]; - u32* ids = (u32*)b3Alloc(n * sizeof(u32)); - for (u32 i = 0; i < n; ++i) + // Sort along longest axis + b3Sort(set, splitAxis, ids, count); + + // Find the object that splits the set in two subsets. + u32 left = 0; + u32 right = count - 1; + u32 middle = left; + while (middle < right) + { + b3Vec3 center = set[ids[middle]].Centroid(); + if (center[splitAxis] > splitPos) + { + // Found median. + break; + } + ++middle; + } + + B3_ASSERT(middle >= left); + B3_ASSERT(middle <= right); + + // Ensure nonempty subsets. + u32 count1 = middle; + u32 count2 = count - middle; + if (count1 == 0 || count2 == 0) + { + middle = (left + right) / 2; + } + + return middle; +} + +void b3StaticTree::Build(const b3AABB3* set, b3Node* node, u32* ids, u32 count, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount) +{ + B3_ASSERT(count > 0); + + // Enclose set + b3AABB3 setAABB = set[ids[0]]; + for (u32 i = 1; i < count; ++i) + { + setAABB = b3Combine(setAABB, set[ids[i]]); + } + + node->aabb = setAABB; + + if (count <= minObjectsPerLeaf) + { + ++leafCount; + node->child1 = NULL_NODE_S; + node->index = ids[0]; + } + else + { + ++internalCount; + + // Partition current set + u32 middle = b3Partition(setAABB, set, ids, count); + + // Allocate left subtree + B3_ASSERT(m_nodeCount < nodeCapacity); + node->child1 = m_nodeCount; + ++m_nodeCount; + + // Allocate right subtree + B3_ASSERT(m_nodeCount < nodeCapacity); + node->child2 = m_nodeCount; + ++m_nodeCount; + + // Build left and right subtrees + Build(set, m_nodes + node->child1, ids, middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount); + Build(set, m_nodes + node->child2, ids + middle, count - middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount); + } +} + +void b3StaticTree::Build(const b3AABB3* set, u32 count) +{ + B3_ASSERT(count > 0); + + u32* ids = (u32*)b3Alloc(count * sizeof(u32)); + for (u32 i = 0; i < count; ++i) { ids[i] = i; } @@ -74,9 +161,9 @@ void b3StaticTree::Build(const b3AABB3* set, u32 n) // each leaf node contains exactly 1 object. const u32 kMinObjectsPerLeaf = 1; - u32 internalCapacity = n - 1; - u32 leafCapacity = n; - u32 nodeCapacity = 2 * n - 1; + u32 internalCapacity = count - 1; + u32 leafCapacity = count; + u32 nodeCapacity = 2 * count - 1; u32 internalCount = 0; u32 leafCount = 0; @@ -84,112 +171,8 @@ void b3StaticTree::Build(const b3AABB3* set, u32 n) m_nodes = (b3Node*)b3Alloc(nodeCapacity * sizeof(b3Node)); m_nodeCount = 1; - b3Stack stack; + Build(set, m_nodes, ids, count, kMinObjectsPerLeaf, nodeCapacity, leafCount, internalCount); - { - b3Params params; - params.node = 0; - params.indices = ids; - params.numObjects = n; - stack.Push(params); - } - - while (stack.Count() > 0) - { - b3Params params = stack.Top(); - stack.Pop(); - - u32 nodeIndex = params.node; - u32* indices = params.indices; - u32 numObjects = params.numObjects; - - B3_ASSERT(numObjects > 0); - - // "Allocate" node - b3Node* node = m_nodes + nodeIndex; - - // Enclose set - b3AABB3 setAABB = set[indices[0]]; - for (u32 i = 1; i < numObjects; ++i) - { - setAABB = b3Combine(setAABB, set[indices[i]]); - } - - node->aabb = setAABB; - - if (numObjects <= kMinObjectsPerLeaf) - { - ++leafCount; - node->child1 = NULL_NODE_S; - node->index = indices[0]; - } - else - { - ++internalCount; - - u32 splitAxis = setAABB.GetLongestAxisIndex(); - float32 splitPos = setAABB.Centroid()[splitAxis]; - - // Sort along longest axis - b3SortPredicate pred; - pred.axis = splitAxis; - pred.bs = set; - std::sort(indices, indices + numObjects, pred); - - // Find the object that splits the set in two subsets. - u32 left = 0; - u32 right = numObjects - 1; - u32 middle = left; - while (middle < right) - { - b3Vec3 center = set[indices[middle]].Centroid(); - if (center[splitAxis] > splitPos) - { - // Found median. - break; - } - ++middle; - } - - B3_ASSERT(middle >= left); - B3_ASSERT(middle <= right); - - // Ensure we don't have empty subsets. - u32 count1 = middle; - u32 count2 = numObjects - middle; - if (count1 == 0 || count2 == 0) - { - // Split at object median. - middle = (left + right) / 2; - count1 = middle; - count2 = numObjects - middle; - } - - B3_ASSERT(count1 > 0 && count2 > 0); - - B3_ASSERT(m_nodeCount < nodeCapacity); - node->child1 = m_nodeCount; - ++m_nodeCount; - - B3_ASSERT(m_nodeCount < nodeCapacity); - node->child2 = m_nodeCount; - ++m_nodeCount; - - // Repeat for childs - b3Params params1; - params1.node = node->child1; - params1.indices = indices; - params1.numObjects = count1; - stack.Push(params1); - - b3Params params2; - params2.node = node->child2; - params2.indices = indices + middle; - params2.numObjects = count2; - stack.Push(params2); - } - } - b3Free(ids); B3_ASSERT(leafCount == leafCapacity);