2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 08:42:35 +00:00
Files
OpenAssetTools/src/ObjLoading/Game/T6/BSP/BSPCalculation.cpp
T

161 lines
4.7 KiB
C++

#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<BSPObject> 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<BSPTree> frontTree, std::unique_ptr<BSPTree> 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<BSPTree> front;
std::unique_ptr<BSPTree> 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<BSPTree>(halfLength, min.y, min.z, max.x, max.y, max.z, level + 1);
back = std::make_unique<BSPTree>(min.x, min.y, min.z, halfLength, max.y, max.z, level + 1);
isLeaf = false;
node = std::make_unique<BSPNode>(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<BSPTree>(min.x, halfLength, min.z, max.x, max.y, max.z, level + 1);
back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, halfLength, max.z, level + 1);
isLeaf = false;
node = std::make_unique<BSPNode>(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<BSPTree>(min.x, min.y, halfLength, max.x, max.y, max.z, level + 1);
back = std::make_unique<BSPTree>(min.x, min.y, min.z, max.x, max.y, halfLength, level + 1);
isLeaf = false;
node = std::make_unique<BSPNode>(std::move(front), std::move(back), AXIS_Z, halfLength);
leaf = nullptr;
}
else
{
isLeaf = true;
node = nullptr;
leaf = std::make_unique<BSPLeaf>();
}
}
void BSPTree::addObjectToTree(std::shared_ptr<BSPObject> 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