diff --git a/src/game/state/boot.cpp b/src/game/state/boot.cpp index b91d6d9..1834669 100644 --- a/src/game/state/boot.cpp +++ b/src/game/state/boot.cpp @@ -652,7 +652,7 @@ void boot::setup_scenes() // Setup surface camera ctx.surface_camera = new scene::camera(); - ctx.surface_camera->set_perspective(math::radians(45.0f), viewport_aspect_ratio, 0.1f, 500.0f); + ctx.surface_camera->set_perspective(math::radians(45.0f), viewport_aspect_ratio, 0.1f, 10000.0f); ctx.surface_camera->set_compositor(ctx.surface_compositor); ctx.surface_camera->set_composite_index(0); ctx.surface_camera->set_active(false); diff --git a/src/game/system/terrain.cpp b/src/game/system/terrain.cpp index fc980f9..93deceb 100644 --- a/src/game/system/terrain.cpp +++ b/src/game/system/terrain.cpp @@ -57,30 +57,6 @@ terrain::terrain(entity::registry& registry): for (std::size_t i = 0; i <= quadtree_type::max_depth; ++i) quadtree_node_size[i] = 0.0f; - - geom::quadtree64 q; - q.insert(q.node(4, 0)); - //q.insert(q.node(8, geom::morton::encode(4, 4))); - - // std::cout << "q size: " << q.size() << std::endl; - // q.erase(q.node(1, 0)); - // std::cout << "q size: " << q.size() << std::endl; - std::cout << "q maxd : " << (std::size_t)q.max_depth << std::endl; - std::cout << "q res : " << (std::size_t)q.resolution << std::endl; - std::cout << "q cap : " << q.max_size() << std::endl; - std::cout << "set cap: " << std::set().max_size() << std::endl; - - - std::cout << "q size: " << q.size() << std::endl; - for (auto it = q.begin(); it != q.end(); ++it) - { - const auto& node = *it; - auto [depth, location] = q.split(node); - std::cout << "depth: " << (std::size_t)depth << "; location: " << (std::size_t)location << std::endl; - } - - - registry.on_construct().connect<&terrain::on_terrain_construct>(this); registry.on_update().connect<&terrain::on_terrain_update>(this); registry.on_destroy().connect<&terrain::on_terrain_destroy>(this); @@ -144,13 +120,19 @@ void terrain::update(double t, double dt) geom::sphere sphere; sphere.center = cam.get_translation(); - sphere.radius = patch_side_length; + //sphere.radius = patch_side_length; + sphere.radius = 1.0f; + + // Determine camera position node + auto translation = cam.get_translation(); //visit_quadtree(cam.get_view_frustum().get_bounds(), quadtree_type::root); visit_quadtree(sphere, quadtree_type::root); } ); + balance_quadtree(); + //std::cout << "qsize: " << quadtree.size() << std::endl; std::size_t qvis = 0; @@ -340,6 +322,46 @@ void terrain::visit_quadtree(const geom::bounding_volume& volume, quadtre } } +void terrain::balance_quadtree() +{ + std::unordered_set nodes; + + for (const auto& node: quadtree) + { + auto [depth, location] = quadtree.split(node); + + // Skip root node + if (depth < 2) + continue; + + quadtree_node_type x, y; + geom::morton::decode(location, x, y); + + --depth; + + if (x < quadtree.resolution - 1) + { + if (y < quadtree.resolution - 1) + nodes.insert(quadtree.node(depth, geom::morton::encode(x + 1, y + 1))); + if (y > 0) + nodes.insert(quadtree.node(depth, geom::morton::encode(x + 1, y - 1))); + } + + if (x > 0) + { + if (y < quadtree.resolution - 1) + nodes.insert(quadtree.node(depth, geom::morton::encode(x - 1, y + 1))); + if (y > 0) + nodes.insert(quadtree.node(depth, geom::morton::encode(x - 1, y - 1))); + } + } + + for (const auto& node: nodes) + { + quadtree.insert(node); + } +} + geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const { // Extract node depth diff --git a/src/game/system/terrain.hpp b/src/game/system/terrain.hpp index 55b94d4..3714565 100644 --- a/src/game/system/terrain.hpp +++ b/src/game/system/terrain.hpp @@ -85,6 +85,8 @@ private: typedef geom::unordered_quadtree16 quadtree_type; typedef typename quadtree_type::node_type quadtree_node_type; + void balance_quadtree(); + struct patch { geom::mesh* mesh; diff --git a/src/geom/hyperoctree.hpp b/src/geom/hyperoctree.hpp index cb8bb21..eee2262 100644 --- a/src/geom/hyperoctree.hpp +++ b/src/geom/hyperoctree.hpp @@ -32,16 +32,16 @@ namespace geom { -/// Orders in which hyperoctree nodes can be stored and iterated. +/// Orders in which hyperoctree nodes can be stored and traversed. enum class hyperoctree_order { /// Hyperoctree nodes are unordered, potentially resulting in faster insertions through the internal use of `std::unordered_set` rather than `std::set`. unordered, - /// Hyperoctree nodes are stored and iterated in depth-first preorder. + /// Hyperoctree nodes are stored and traversed in depth-first preorder. dfs_pre, - /// Hyperoctree nodes are stored and iterated in breadth-first order. + /// Hyperoctree nodes are stored and traversed in breadth-first order. bfs }; @@ -89,7 +89,7 @@ struct hyperoctree_container * * @tparam T Unsigned integral node identifier type. * @tparam N Number of dimensions. - * @tparam Order Order in which nodes are stored and iterated. + * @tparam Order Order in which nodes are stored and traversed. * * @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html * @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/ @@ -309,7 +309,7 @@ public: } /** - * Constructs an identifier for first common ancestor of two nodes + * Constructs an identifier for the first common ancestor of two nodes * * @param a Identifier of the first node. * @param b Identifier of the second node. @@ -470,7 +470,7 @@ public: } /// Returns the total number of nodes the hyperoctree is capable of containing. - static consteval std::size_t max_size() noexcept + consteval std::size_t max_size() const noexcept { return max_node_count; } @@ -487,7 +487,7 @@ public: } /** - * Inserts a node and its siblings into the hyperoctree, creating ancestors as necessary. + * Inserts a node and its siblings into the hyperoctree, inserting ancestors as necessary. * * @param node Node to insert. * diff --git a/src/geom/morton.hpp b/src/geom/morton.hpp index 3006130..d3c87bc 100644 --- a/src/geom/morton.hpp +++ b/src/geom/morton.hpp @@ -20,8 +20,7 @@ #ifndef ANTKEEPER_GEOM_MORTON_HPP #define ANTKEEPER_GEOM_MORTON_HPP -#include -#include +#include namespace geom { @@ -33,45 +32,11 @@ namespace morton { * * @param[in] x X-coordinate to encode. * @param[in] y Y-coordinate to encode. - * @return Morton location code. - */ -template -T encode(T x, T y); - -/** - * Encodes 3D coordinates as a Morton location code. * - * @param[in] x X-coordinate to encode. - * @param[in] y Y-coordinate to encode. - * @param[in] z Z-coordinate to encode. * @return Morton location code. */ -template -T encode(T x, T y, T z); - -/** - * Decodes 2D coordinates from a Morton location code. - * - * @param[in] code Morton location code to decode. - * @param[out] x Decoded x-coordinate. - * @param[out] y Decoded y-coordinate. - */ -template -void decode(T code, T& x, T& y); - -/** - * Decodes 3D coordinates from a Morton location code. - * - * @param[in] code Morton location code to decode. - * @param[out] x Decoded x-coordinate. - * @param[out] y Decoded y-coordinate. - * @param[out] z Decoded z-coordinate. - */ -template -void decode(T code, T& x, T& y, T& z); - -template -T encode(T x, T y) +template +constexpr T encode(T x, T y) noexcept { auto expand = [](T x) -> T { @@ -93,8 +58,17 @@ T encode(T x, T y) return expand(x) | (expand(y) << 1); } -template -T encode(T x, T y, T z) +/** + * Encodes 3D coordinates as a Morton location code. + * + * @param[in] x X-coordinate to encode. + * @param[in] y Y-coordinate to encode. + * @param[in] z Z-coordinate to encode. + * + * @return Morton location code. + */ +template +constexpr T encode(T x, T y, T z) noexcept { auto expand = [](T x) -> T { @@ -134,8 +108,15 @@ T encode(T x, T y, T z) return expand(x) | (expand(y) << 1) | (expand(z) << 2); } -template -void decode(T code, T& x, T& y) +/** + * Decodes 2D coordinates from a Morton location code. + * + * @param[in] code Morton location code to decode. + * @param[out] x Decoded x-coordinate. + * @param[out] y Decoded y-coordinate. + */ +template +void decode(T code, T& x, T& y) noexcept { auto compress = [](T x) -> T { @@ -158,8 +139,16 @@ void decode(T code, T& x, T& y) y = compress(code >> 1); } -template -void decode(T code, T& x, T& y, T& z) +/** + * Decodes 3D coordinates from a Morton location code. + * + * @param[in] code Morton location code to decode. + * @param[out] x Decoded x-coordinate. + * @param[out] y Decoded y-coordinate. + * @param[out] z Decoded z-coordinate. + */ +template +void decode(T code, T& x, T& y, T& z) noexcept { auto compress = [](T x) -> T { diff --git a/src/math/vector.hpp b/src/math/vector.hpp index fb18685..c9cea37 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -49,6 +49,8 @@ struct vector /// Array of vector elements. element_type elements[N]; + /// @name Element access + /// @{ /** * Returns a reference to the element at a given index. * @@ -91,6 +93,18 @@ struct vector } /// @} + /// Returns a pointer to the element array. + /// @{ + constexpr inline element_type* data() noexcept + { + return elements; + }; + constexpr inline const element_type* data() const noexcept + { + return elements; + }; + /// @} + /// Returns a reference to the first element. /// @{ constexpr inline element_type& x() noexcept @@ -132,19 +146,10 @@ struct vector return elements[2]; } /// @} - - /// Returns a pointer to the element array. - /// @{ - constexpr inline element_type* data() noexcept - { - return elements; - }; - constexpr inline const element_type* data() const noexcept - { - return elements; - }; /// @} + /// @name Iterators + /// @{ /// Returns an iterator to the first element. /// @{ constexpr inline element_type* begin() noexcept @@ -208,12 +213,16 @@ struct vector return std::reverse_iterator(elements); } /// @} + /// @} + /// @name Capacity + /// @{ /// Returns the number of elements in the vector. constexpr inline std::size_t size() const noexcept { return N; }; + /// @} /// @private template @@ -469,6 +478,28 @@ constexpr vector fma(const vector& x, T y, T z); template constexpr vector fract(const vector& x); +/** + * Extracts the Ith element from a vector. + * + * @tparam I Index of an element. + * @tparam T Element type. + * @tparam N Number of elements. + * + * @param v Vector from which to extract an element. + * + * @return Reference to the Ith element of @p v. + */ +/// @{ +template +constexpr T& get(math::vector& v) noexcept; +template +constexpr T&& get(math::vector&& v) noexcept; +template +constexpr const T& get(const math::vector& v) noexcept; +template +constexpr const T&& get(const math::vector&& v) noexcept; +/// @} + /** * Performs a element-wise greater-than comparison of two vectors. * @@ -1011,6 +1042,34 @@ constexpr inline vector fract(const vector& x) return fract(x, std::make_index_sequence{}); } +template +constexpr inline T& get(math::vector& v) noexcept +{ + static_assert(I < N); + return v.elements[I]; +} + +template +constexpr inline T&& get(math::vector&& v) noexcept +{ + static_assert(I < N); + return std::move(v.elements[I]); +} + +template +constexpr inline const T& get(const math::vector& v) noexcept +{ + static_assert(I < N); + return v.elements[I]; +} + +template +constexpr inline const T&& get(const math::vector&& v) noexcept +{ + static_assert(I < N); + return std::move(v.elements[I]); +} + /// @private template constexpr inline vector greater_than(const vector& x, const vector& y, std::index_sequence) noexcept @@ -1586,6 +1645,37 @@ std::istream& operator>>(std::istream& is, vector& x) } // namespace math +// Bring vector operators into global namespace using namespace math::operators; +// Structured binding support +namespace std +{ + /** + * Provides access to the number of elements in a math::vector as a compile-time constant expression. + * + * @tparam T Element type. + * @tparam N Number of elements. + */ + template + struct tuple_size> + { + /// Number of elements in the vector. + static constexpr std::size_t value = N; + }; + + /** + * Provides compile-time indexed access to the type of the elements in a math::vector using a tuple-like interface. + * + * @tparam T Element type. + * @tparam N Number of elements. + */ + template + struct tuple_element> + { + /// Type of elements in the vector. + using type = T; + }; +} + #endif // ANTKEEPER_MATH_VECTOR_HPP