mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 12:09:19 +02:00
Ordering them before the imports in the same file was not enough: a project header on line 1 can import a module several levels down whose global module fragment already pulled in the same standard header, and that include guard does not cross the module boundary. Putting them first means the guard is set before anything can import. Skips vendored single-header libraries and anything inside an #if.
98 lines
3.1 KiB
C++
98 lines
3.1 KiB
C++
#include <cstdint>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include "nvrenderer/quadtree.h"
|
|
|
|
void QuadTreeBuilder::Node::Insert(uint32_t index, glm::dvec3 min_,
|
|
glm::dvec3 max_, int level) {
|
|
if (level > 0) {
|
|
int child = GetChildIndex(.5 * (min_ + max_));
|
|
if (!m_children[child]) {
|
|
m_children[child] = std::make_shared<Node>(GetChildBounds(child));
|
|
}
|
|
m_children[child]->Insert(index, min_, max_, level - 1);
|
|
} else {
|
|
m_leaves.emplace_back(.5 * (max_ + min_), .5 * (max_ - min_), index);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if (compMin(m_actual_min) < -1.e10) {
|
|
__debugbreak();
|
|
}
|
|
if (compMax(m_actual_max) > 1.e10) {
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
|
|
m_actual_min = min(min_, m_actual_min);
|
|
m_actual_max = max(max_, m_actual_max);
|
|
|
|
#ifndef NDEBUG
|
|
if (compMax(glm::abs(m_actual_min)) > 1.e10) {
|
|
__debugbreak();
|
|
}
|
|
if (compMax(glm::abs(m_actual_max)) > 1.e10) {
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
QuadTreeBuilder::QuadTreeBuilder(double min_x, double min_z, double max_x,
|
|
double max_z)
|
|
: m_root(std::make_shared<Node>(min_x, min_z, max_x, max_z)),
|
|
m_min(min_x, -std::numeric_limits<double>::max(), min_z),
|
|
m_max(max_x, std::numeric_limits<double>::max(), max_z),
|
|
m_max_levels(32) {
|
|
// Ensure outer bounds are square
|
|
glm::dvec2 origin = .5 * (m_max + m_min).xz;
|
|
glm::dvec2 extent = .5 * (m_max - m_min).xz;
|
|
extent = glm::dvec2(glm::compMax(extent));
|
|
m_min.xz = origin - extent;
|
|
m_max.xz = origin + extent;
|
|
// glm::dvec3 scale_v = (m_max - m_min) / 50.;
|
|
// double scale = glm::min(scale_v.z, scale_v.x);
|
|
// m_max_levels = glm::max(1, (int)glm::ceil(glm::log2(scale)));
|
|
}
|
|
|
|
void QuadTreeBuilder::Insert(uint32_t index, glm::dvec3 min,
|
|
glm::dvec3 max) const {
|
|
glm::dvec3 scale_v = (m_max - m_min) / (max - min);
|
|
double scale = glm::min(scale_v.z, scale_v.x);
|
|
int level =
|
|
glm::clamp((int)glm::floor(glm::log2(scale)), 0, m_max_levels - 1);
|
|
m_root->Insert(index, min, max, level);
|
|
}
|
|
|
|
void QuadTree::Build(const QuadTreeBuilder& builder) {
|
|
Add(m_nodes.emplace_back(), *builder.m_root);
|
|
}
|
|
|
|
void QuadTree::Add(Node& node, const QuadTreeBuilder::Node& item) {
|
|
if (item.m_leaves.empty() && item.NumChildren() == 1) {
|
|
return Add(node, *item.FirstChild());
|
|
}
|
|
node.m_origin = .5 * (item.m_actual_max + item.m_actual_min);
|
|
node.m_extent = .5 * (item.m_actual_max - item.m_actual_min);
|
|
node.m_first_leave = m_leaves.size();
|
|
node.m_leave_count = item.m_leaves.size();
|
|
m_leaves.insert(m_leaves.end(), item.m_leaves.begin(), item.m_leaves.end());
|
|
uint32_t first_child = m_nodes.size();
|
|
uint32_t child_count = 0;
|
|
for (const auto& child : item.m_children) {
|
|
if (child) ++child_count;
|
|
}
|
|
node.m_first_child = first_child;
|
|
node.m_child_count = child_count;
|
|
// node reference invalidated from here
|
|
for (int i = 0; i < child_count; ++i) {
|
|
m_nodes.emplace_back();
|
|
}
|
|
{
|
|
int child_index = first_child;
|
|
for (const auto& child : item.m_children) {
|
|
if (!child) continue;
|
|
Add(m_nodes[child_index++], *child);
|
|
}
|
|
}
|
|
}
|