#include "BSPCalculation.h" namespace BSP { constexpr int MAX_NODE_SIZE = 512; // maximum size a BSP node can be before it becomes a leaf BSPObject::BSPObject(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex) { min.x = xMin; min.y = yMin; min.z = zMin; max.x = xMax; max.y = yMax; max.z = zMax; partitionIndex = objPartitionIndex; } void BSPLeaf::addObject(std::shared_ptr object) { objectList.emplace_back(std::move(object)); } BSPObject* BSPLeaf::getObject(size_t index) { return objectList.at(index).get(); } size_t BSPLeaf::getObjectCount() { return objectList.size(); } BSPNode::BSPNode(std::unique_ptr frontTree, std::unique_ptr backTree, PlaneAxis nodeAxis, float nodeDistance) { front = std::move(frontTree); back = std::move(backTree); axis = nodeAxis; distance = nodeDistance; } PlaneSide BSPNode::objectIsInFront(BSPObject* object) { float minCoord, maxCoord; // Select the relevant coordinate based on the plane's axis if (axis == AXIS_X) { minCoord = object->min.x; maxCoord = object->max.x; } else if (axis == AXIS_Y) { minCoord = object->min.y; maxCoord = object->max.y; } else // axis == AXIS_Z { minCoord = object->min.z; maxCoord = object->max.z; } // Compare with the plane's distance if (maxCoord < distance) { return SIDE_BACK; // Object is entirely on the negative side } else if (minCoord > distance) { return SIDE_FRONT; // Object is entirely on the positive side } else { return SIDE_INTERSECTS; } } BSPTree::BSPTree(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int treeLevel) { min.x = xMin; min.y = yMin; min.z = zMin; max.x = xMax; max.y = yMax; max.z = zMax; level = treeLevel; splitTree(); } void BSPTree::splitTree() { std::unique_ptr front; std::unique_ptr back; float halfLength; if (max.x - min.x > MAX_NODE_SIZE) { // split along the x axis halfLength = (min.x + max.x) * 0.5f; front = std::make_unique(halfLength, min.y, min.z, max.x, max.y, max.z, level + 1); back = std::make_unique(min.x, min.y, min.z, halfLength, max.y, max.z, level + 1); isLeaf = false; node = std::make_unique(std::move(front), std::move(back), AXIS_X, halfLength); leaf = nullptr; } else if (max.y - min.y > MAX_NODE_SIZE) { // split along the x axis halfLength = (min.y + max.y) * 0.5f; front = std::make_unique(min.x, halfLength, min.z, max.x, max.y, max.z, level + 1); back = std::make_unique(min.x, min.y, min.z, max.x, halfLength, max.z, level + 1); isLeaf = false; node = std::make_unique(std::move(front), std::move(back), AXIS_Y, halfLength); leaf = nullptr; } else if (max.z - min.z > MAX_NODE_SIZE) { // split along the z axis halfLength = (min.z + max.z) * 0.5f; front = std::make_unique(min.x, min.y, halfLength, max.x, max.y, max.z, level + 1); back = std::make_unique(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1); isLeaf = false; node = std::make_unique(std::move(front), std::move(back), AXIS_Z, halfLength); leaf = nullptr; } else { isLeaf = true; node = nullptr; leaf = std::make_unique(); } } void BSPTree::addObjectToTree(std::shared_ptr object) { if (isLeaf) { leaf->addObject(std::move(object)); } else { PlaneSide side = node->objectIsInFront(object.get()); if (side == SIDE_FRONT) { node->front->addObjectToTree(std::move(object)); } else if (side == SIDE_BACK) { node->back->addObjectToTree(std::move(object)); } else // intersects { node->front->addObjectToTree(object); node->back->addObjectToTree(object); } } } } // namespace BSP