Program Listing for File cube.hpp¶
↰ Return to documentation for file (inexor/vulkan-renderer/world/cube.hpp
)
#pragma once
#include "inexor/vulkan-renderer/world/indentation.hpp"
#include <glm/gtx/vector_angle.hpp>
#include <glm/vec3.hpp>
#include <array>
#include <functional>
#include <memory>
#include <optional>
#include <vector>
// Forward declaration
namespace inexor::vulkan_renderer::world {
class Cube;
} // namespace inexor::vulkan_renderer::world
// Forward declarations
namespace inexor::vulkan_renderer::io {
class ByteStream;
class NXOCParser;
} // namespace inexor::vulkan_renderer::io
void swap(inexor::vulkan_renderer::world::Cube &lhs, inexor::vulkan_renderer::world::Cube &rhs) noexcept;
namespace inexor::vulkan_renderer::world {
using Polygon = std::array<glm::vec3, 3>;
using PolygonCache = std::shared_ptr<std::vector<Polygon>>;
class Cube : public std::enable_shared_from_this<Cube> {
friend void ::swap(Cube &lhs, Cube &rhs) noexcept;
friend class io::NXOCParser;
public:
static constexpr std::size_t SUB_CUBES{8};
static constexpr std::size_t EDGES{12};
enum class Type { EMPTY = 0b00u, SOLID = 0b01u, NORMAL = 0b10u, OCTANT = 0b11u };
enum class NeighborAxis { X = 2, Y = 1, Z = 0 };
enum class NeighborDirection { POSITIVE, NEGATIVE };
struct RotationAxis {
using ChildType = std::array<std::array<std::size_t, 4>, 2>;
using EdgeType = std::array<std::array<std::size_t, 4>, 3>;
using Type = std::pair<ChildType, EdgeType>;
static constexpr Type X{{{{0, 1, 3, 2}, {4, 5, 7, 6}}}, {{{2, 4, 11, 1}, {5, 7, 8, 10}, {0, 9, 6, 3}}}};
static constexpr Type Y{{{{0, 4, 5, 1}, {2, 6, 7, 3}}}, {{{0, 5, 9, 2}, {3, 8, 6, 11}, {1, 10, 7, 4}}}};
static constexpr Type Z{{{{0, 2, 6, 4}, {1, 3, 7, 5}}}, {{{1, 3, 10, 0}, {4, 6, 7, 9}, {2, 11, 8, 5}}}};
};
private:
Type m_type{Type::EMPTY};
float m_size{32};
glm::vec3 m_position{0.0f, 0.0f, 0.0f};
std::weak_ptr<Cube> m_parent{};
std::uint8_t m_index_in_parent{};
std::array<Indentation, Cube::EDGES> m_indentations;
std::array<std::shared_ptr<Cube>, Cube::SUB_CUBES> m_children;
mutable PolygonCache m_polygon_cache;
mutable bool m_polygon_cache_valid{false};
void remove_children();
[[nodiscard]] std::shared_ptr<Cube> root();
[[nodiscard]] std::array<glm::vec3, 8> vertices() const noexcept;
template <int Rotations>
void rotate(const RotationAxis::Type &axis);
public:
Cube() = default;
Cube(float size, const glm::vec3 &position);
Cube(std::weak_ptr<Cube> parent, std::uint8_t index, float size, const glm::vec3 &position);
Cube(const Cube &rhs) = delete;
Cube(Cube &&rhs) noexcept;
~Cube() = default;
Cube &operator=(Cube rhs);
Cube &operator=(Cube &&) = delete;
std::shared_ptr<Cube> operator[](std::size_t idx);
std::shared_ptr<const Cube> operator[](std::size_t idx) const; // NOLINT
[[nodiscard]] std::shared_ptr<Cube> clone() const;
[[nodiscard]] bool is_root() const noexcept;
[[nodiscard]] std::size_t grid_level() const noexcept;
[[nodiscard]] std::size_t count_geometry_cubes() const noexcept;
[[nodiscard]] glm::vec3 center() const noexcept {
return m_position + 0.5f * m_size;
}
[[nodiscard]] glm::vec3 position() const noexcept {
return m_position;
}
[[nodiscard]] std::array<glm::vec3, 2> bounding_box() const {
return {m_position, {m_position.x + m_size, m_position.y + m_size, m_position.z + m_size}};
}
[[nodiscard]] float size() const noexcept {
return m_size;
}
void set_type(Type new_type);
[[nodiscard]] Type type() const noexcept;
[[nodiscard]] const std::array<std::shared_ptr<Cube>, Cube::SUB_CUBES> &children() const;
[[nodiscard]] std::array<Indentation, Cube::EDGES> indentations() const noexcept;
void set_indent(std::uint8_t edge_id, Indentation indentation);
void indent(std::uint8_t edge_id, bool positive_direction, std::uint8_t steps);
void rotate(const RotationAxis::Type &axis, int rotations);
void update_polygon_cache() const;
void invalidate_polygon_cache() const;
[[nodiscard]] std::vector<PolygonCache> polygons(bool update_invalid = false) const;
[[nodiscard]] std::shared_ptr<Cube> neighbor(NeighborAxis axis, NeighborDirection direction);
};
std::shared_ptr<world::Cube> create_random_world(std::uint32_t max_depth, const glm::vec3 &position,
std::optional<std::uint32_t> seed = std::nullopt);
} // namespace inexor::vulkan_renderer::world