Browse Source

Make source compatible with latest version of MSVC. Add compile-time math header

master
C. J. Howard 2 years ago
parent
commit
ff4917825f
22 changed files with 208 additions and 177 deletions
  1. +0
    -1
      CMakeLists.txt
  2. +32
    -32
      src/ai/bt/node.hpp
  3. +2
    -0
      src/animation/spring.hpp
  4. +1
    -0
      src/animation/tween.hpp
  5. +1
    -1
      src/color/xyy.hpp
  6. +1
    -1
      src/color/xyz.hpp
  7. +1
    -1
      src/config.hpp.in
  8. +1
    -1
      src/game/ant/swarm.cpp
  9. +2
    -2
      src/game/system/astronomy.cpp
  10. +9
    -5
      src/game/system/terrain.cpp
  11. +1
    -3
      src/game/system/terrain.hpp
  12. +2
    -2
      src/genetics/base.cpp
  13. +67
    -105
      src/geom/hyperoctree.hpp
  14. +6
    -6
      src/geom/octree.hpp
  15. +6
    -6
      src/geom/quadtree.hpp
  16. +61
    -0
      src/math/compile.hpp
  17. +2
    -2
      src/math/matrix.hpp
  18. +1
    -1
      src/math/transform-type.hpp
  19. +4
    -4
      src/math/vector.hpp
  20. +3
    -1
      src/resources/behavior-tree-loader.cpp
  21. +4
    -2
      src/resources/entity-archetype-loader.cpp
  22. +1
    -1
      src/resources/resource-manager.hpp

+ 0
- 1
CMakeLists.txt View File

@ -23,7 +23,6 @@ set(STATIC_LIBS
stb stb
tinyexr tinyexr
glad glad
EnTT
SDL2::SDL2-static SDL2::SDL2-static
SDL2::SDL2main SDL2::SDL2main
OpenAL::OpenAL OpenAL::OpenAL

+ 32
- 32
src/ai/bt/node.hpp View File

@ -51,98 +51,98 @@ using leaf_node = node;
/// A node with exactly one child. /// A node with exactly one child.
template <class T> template <class T>
struct decorator_node: node<T>
struct decorator_node: public node<T>
{ {
node* child;
node<T>* child;
}; };
/// A node that can have one or more children. /// A node that can have one or more children.
template <class T> template <class T>
struct composite_node: node<T>
struct composite_node: public node<T>
{ {
std::list<node*> children;
std::list<node<T>*> children;
}; };
/// Executes a function on a context and returns the status. /// Executes a function on a context and returns the status.
template <class T> template <class T>
struct action: leaf_node<T>
struct action: public leaf_node<T>
{ {
virtual status execute(context_type& context) const final;
typedef std::function<status(context_type&)> function_type;
virtual status execute(node<T>::context_type& context) const final;
typedef std::function<status(node<T>::context_type&)> function_type;
function_type function; function_type function;
}; };
/// Evaluates a boolean condition (predicate) and returns either `status::success` or `status::failure`. /// Evaluates a boolean condition (predicate) and returns either `status::success` or `status::failure`.
template <class T> template <class T>
struct condition: leaf_node<T>
struct condition: public leaf_node<T>
{ {
virtual status execute(context_type& context) const final;
typedef std::function<status(const context_type&)> predicate_type;
virtual status execute(node<T>::context_type& context) const final;
typedef std::function<status(const node<T>::context_type&)> predicate_type;
predicate_type predicate; predicate_type predicate;
}; };
/// Executes a child node and returns its inverted status. If the child returns `status::success`, then `status::failure` will be returned. Otherwise if the child returns `status::failure`, then `status::success` will be returned. /// Executes a child node and returns its inverted status. If the child returns `status::success`, then `status::failure` will be returned. Otherwise if the child returns `status::failure`, then `status::success` will be returned.
template <class T> template <class T>
struct inverter: decorator_node<T>
struct inverter: public decorator_node<T>
{ {
virtual status execute(context_type& context) const final;
virtual status execute(node<T>::context_type& context) const final;
}; };
/// Attempts to execute a child node `n` times or until the child fails. /// Attempts to execute a child node `n` times or until the child fails.
template <class T> template <class T>
struct repeater: decorator_node<T>
struct repeater: public decorator_node<T>
{ {
virtual status execute(context_type& context) const final;
virtual status execute(node<T>::context_type& context) const final;
int n; int n;
}; };
/// Executes a child node and returns `status::success` regardless of the child node status. /// Executes a child node and returns `status::success` regardless of the child node status.
template <class T> template <class T>
struct succeeder: decorator_node<T>
struct succeeder: public decorator_node<T>
{ {
virtual status execute(context_type& context) const final;
virtual status execute(node<T>::context_type& context) const final;
}; };
/// Attempts to execute each child node sequentially until one fails. If all children are executed successfully, `status::success` will be returned. Otherwise if any children fail, `status::failure` will be returned. /// Attempts to execute each child node sequentially until one fails. If all children are executed successfully, `status::success` will be returned. Otherwise if any children fail, `status::failure` will be returned.
template <class T> template <class T>
struct sequence: composite_node<T>
struct sequence: public composite_node<T>
{ {
virtual status execute(context_type& context) const final;
virtual status execute(node<T>::context_type& context) const final;
}; };
/// Attempts to execute each child node sequentially until one succeeds. If a child succeeds, `status::success` will be returned. Otherwise if all children fail, `status::failure` will be returned. /// Attempts to execute each child node sequentially until one succeeds. If a child succeeds, `status::success` will be returned. Otherwise if all children fail, `status::failure` will be returned.
template <class T> template <class T>
struct selector: composite_node<T>
struct selector: public composite_node<T>
{ {
virtual status execute(context_type& context) const final;
virtual status execute(node<T>::context_type& context) const final;
}; };
template <class T> template <class T>
status action<T>::execute(context_type& context) const
status action<T>::execute(node<T>::context_type& context) const
{ {
return function(context); return function(context);
} }
template <class T> template <class T>
status condition<T>::execute(context_type& context) const
status condition<T>::execute(node<T>::context_type& context) const
{ {
return (predicate(context)) ? status::success : status::failure; return (predicate(context)) ? status::success : status::failure;
} }
template <class T> template <class T>
status inverter<T>::execute(context_type& context) const
status inverter<T>::execute(node<T>::context_type& context) const
{ {
status child_status = child->execute(context);
status child_status = decorator_node<T>::child->execute(context);
return (child_status == status::success) ? status::failure : (child_status == status::failure) ? status::success : child_status; return (child_status == status::success) ? status::failure : (child_status == status::failure) ? status::success : child_status;
} }
template <class T> template <class T>
status repeater<T>::execute(context_type& context) const
status repeater<T>::execute(node<T>::context_type& context) const
{ {
status child_status; status child_status;
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
child_status = child->execute(context);
child_status = decorator_node<T>::child->execute(context);
if (child_status == status::failure) if (child_status == status::failure)
break; break;
} }
@ -150,16 +150,16 @@ status repeater::execute(context_type& context) const
} }
template <class T> template <class T>
status succeeder<T>::execute(context_type& context) const
status succeeder<T>::execute(node<T>::context_type& context) const
{ {
child->execute(context);
decorator_node<T>::child->execute(context);
return status::success; return status::success;
} }
template <class T> template <class T>
status sequence<T>::execute(context_type& context) const
status sequence<T>::execute(node<T>::context_type& context) const
{ {
for (const node* child: children)
for (const node<T>* child: composite_node<T>::children)
{ {
status child_status = child->execute(context); status child_status = child->execute(context);
if (child_status != status::success) if (child_status != status::success)
@ -169,9 +169,9 @@ status sequence::execute(context_type& context) const
} }
template <class T> template <class T>
status selector<T>::execute(context_type& context) const
status selector<T>::execute(node<T>::context_type& context) const
{ {
for (const node* child: children)
for (const node<T>* child: composite_node<T>::children)
{ {
status child_status = child->execute(context); status child_status = child->execute(context);
if (child_status != status::failure) if (child_status != status::failure)

+ 2
- 0
src/animation/spring.hpp View File

@ -20,6 +20,8 @@
#ifndef ANTKEEPER_SPRING_HPP #ifndef ANTKEEPER_SPRING_HPP
#define ANTKEEPER_SPRING_HPP #define ANTKEEPER_SPRING_HPP
#include "math/constants.hpp"
/** /**
* Contains the variables required for numeric springing. * Contains the variables required for numeric springing.
* *

+ 1
- 0
src/animation/tween.hpp View File

@ -22,6 +22,7 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <stdexcept>
#include <type_traits> #include <type_traits>
/** /**

+ 1
- 1
src/color/xyy.hpp View File

@ -48,7 +48,7 @@ constexpr inline T luminance(const math::vector3& x)
template <class T> template <class T>
constexpr math::vector2<T> to_ucs(const math::vector3<T>& x) constexpr math::vector2<T> to_ucs(const math::vector3<T>& x)
{ {
const T d = T({1} / (T{-2} * x[0] + T{12} * x[1] + T{3}));
const T d = (T{1} / (T{-2} * x[0] + T{12} * x[1] + T{3}));
return math::vector2<T>{(T{4} * x[0]) * d, (T{6} * x[1]) * d}; return math::vector2<T>{(T{4} * x[0]) * d, (T{6} * x[1]) * d};
} }

+ 1
- 1
src/color/xyz.hpp View File

@ -53,7 +53,7 @@ template
constexpr math::vector3<T> to_xyy(const math::vector3<T>& x) constexpr math::vector3<T> to_xyy(const math::vector3<T>& x)
{ {
const T sum = x[0] + x[1] + x[2]; const T sum = x[0] + x[1] + x[2];
return math::vector3<T>{x[0] / sum, x[1] / sum, x[1]}
return math::vector3<T>{x[0] / sum, x[1] / sum, x[1]};
} }
/** /**

+ 1
- 1
src/config.hpp.in View File

@ -28,7 +28,7 @@ namespace config {
constexpr int version_major = @PROJECT_VERSION_MAJOR@; constexpr int version_major = @PROJECT_VERSION_MAJOR@;
constexpr int version_minor = @PROJECT_VERSION_MINOR@; constexpr int version_minor = @PROJECT_VERSION_MINOR@;
constexpr int version_patch = @PROJECT_VERSION_PATCH@; constexpr int version_patch = @PROJECT_VERSION_PATCH@;
constexpr char* version_string = "@PROJECT_VERSION@";
constexpr const char* version_string = "@PROJECT_VERSION@";
constexpr math::vector<float, 3> global_forward = {0.0f, 0.0f, -1.0f}; constexpr math::vector<float, 3> global_forward = {0.0f, 0.0f, -1.0f};
constexpr math::vector<float, 3> global_up = {0.0f, 1.0f, 0.0f}; constexpr math::vector<float, 3> global_up = {0.0f, 1.0f, 0.0f};

+ 1
- 1
src/game/ant/swarm.cpp View File

@ -39,7 +39,7 @@ namespace ant {
template <class T, class Generator> template <class T, class Generator>
static math::vector3<T> sphere_random(Generator& rng) static math::vector3<T> sphere_random(Generator& rng)
{ {
const std::uniform_real_distribution<T> distribution(T{-1}, T{1});
std::uniform_real_distribution<T> distribution(T{-1}, T{1});
math::vector3<T> position; math::vector3<T> position;
for (std::size_t i = 0; i < 3; ++i) for (std::size_t i = 0; i < 3; ++i)

+ 2
- 2
src/game/system/astronomy.cpp View File

@ -168,7 +168,7 @@ void astronomy::update(double t, double dt)
// Update blackbody lighting // Update blackbody lighting
registry.view<component::celestial_body, component::orbit, component::blackbody>().each( registry.view<component::celestial_body, component::orbit, component::blackbody>().each(
[&](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
[&, bounce_normal](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
{ {
// Transform blackbody position from ICRF frame to EUS frame // Transform blackbody position from ICRF frame to EUS frame
const double3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position; const double3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position;
@ -248,7 +248,7 @@ void astronomy::update(double t, double dt)
// Update diffuse reflectors // Update diffuse reflectors
this->registry.view<component::celestial_body, component::orbit, component::diffuse_reflector, component::transform>().each( this->registry.view<component::celestial_body, component::orbit, component::diffuse_reflector, component::transform>().each(
[&](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
[&, bounce_normal](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
{ {
// Transform reflector position from ICRF frame to EUS frame // Transform reflector position from ICRF frame to EUS frame
const double3 reflector_position_eus = icrf_to_eus * reflector_orbit.position; const double3 reflector_position_eus = icrf_to_eus * reflector_orbit.position;

+ 9
- 5
src/game/system/terrain.cpp View File

@ -56,6 +56,8 @@ terrain::terrain(entity::registry& registry):
for (std::size_t i = 0; i <= quadtree_type::max_depth; ++i) for (std::size_t i = 0; i <= quadtree_type::max_depth; ++i)
quadtree_node_size[i] = 0.0f; quadtree_node_size[i] = 0.0f;
std::cout << "quadtree cap: " << quadtree.max_size() << std::endl;
registry.on_construct<component::terrain>().connect<&terrain::on_terrain_construct>(this); registry.on_construct<component::terrain>().connect<&terrain::on_terrain_construct>(this);
registry.on_update<component::terrain>().connect<&terrain::on_terrain_update>(this); registry.on_update<component::terrain>().connect<&terrain::on_terrain_update>(this);
registry.on_destroy<component::terrain>().connect<&terrain::on_terrain_destroy>(this); registry.on_destroy<component::terrain>().connect<&terrain::on_terrain_destroy>(this);
@ -119,7 +121,7 @@ void terrain::update(double t, double dt)
geom::sphere<float> sphere; geom::sphere<float> sphere;
sphere.center = cam.get_translation(); sphere.center = cam.get_translation();
sphere.radius = cam.get_clip_far() * 0.25;
sphere.radius = patch_side_length;
//visit_quadtree(cam.get_view_frustum().get_bounds(), quadtree_type::root); //visit_quadtree(cam.get_view_frustum().get_bounds(), quadtree_type::root);
visit_quadtree(sphere, quadtree_type::root); visit_quadtree(sphere, quadtree_type::root);
@ -275,14 +277,14 @@ void terrain::visit_quadtree(const geom::bounding_volume& volume, quadtre
node_bounds.min_point = node_bounds.min_point =
{ {
node_center.x() - node_size * 0.5f, node_center.x() - node_size * 0.5f,
quadtree_node_size[quadtree_type::max_depth] * -0.5f,
-std::numeric_limits<float>::infinity(),
node_center.z() - node_size * 0.5f node_center.z() - node_size * 0.5f
}; };
node_bounds.max_point = node_bounds.max_point =
{ {
node_bounds.min_point[0] + node_size,
node_bounds.min_point[1] + quadtree_node_size[quadtree_type::max_depth],
node_bounds.min_point[2] + node_size
node_bounds.min_point.x() + node_size,
std::numeric_limits<float>::infinity(),
node_bounds.min_point.z() + node_size
}; };
// If volume intersects node // If volume intersects node
@ -664,6 +666,8 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
// Set patch model bounds // Set patch model bounds
patch_model->set_bounds(patch_bounds); patch_model->set_bounds(patch_bounds);
//std::cout << "depth: " << quadtree_type::depth(node) << "; size: " << (patch_bounds.max_point + patch_bounds.min_point) * 0.5f << std::endl;
return patch_model; return patch_model;
} }

+ 1
- 3
src/game/system/terrain.hpp View File

@ -82,7 +82,7 @@ public:
void set_scene_collection(scene::collection* collection); void set_scene_collection(scene::collection* collection);
private: private:
typedef geom::quadtree32 quadtree_type;
typedef geom::quadtree16 quadtree_type;
typedef quadtree_type::node_type quadtree_node_type; typedef quadtree_type::node_type quadtree_node_type;
struct patch struct patch
@ -105,8 +105,6 @@ private:
void visit_quadtree(const geom::bounding_volume<float>& volume, quadtree_node_type node); void visit_quadtree(const geom::bounding_volume<float>& volume, quadtree_node_type node);
/** /**
* Generates a mesh for a terrain patch given the patch's quadtree node * Generates a mesh for a terrain patch given the patch's quadtree node
*/ */

+ 2
- 2
src/genetics/base.cpp View File

@ -81,7 +81,7 @@ namespace dna
{ {
char complement(char symbol) char complement(char symbol)
{ {
static constexpr char* complements = "TVGHZZCDZZMZKNZZZYSAABWZR";
constexpr const char* complements = "TVGHZZCDZZMZKNZZZYSAABWZR";
return (symbol < 'A' || symbol >= 'Z') ? 'Z' : complements[symbol - 'A']; return (symbol < 'A' || symbol >= 'Z') ? 'Z' : complements[symbol - 'A'];
} }
} }
@ -90,7 +90,7 @@ namespace rna
{ {
char complement(char symbol) char complement(char symbol)
{ {
static constexpr char* complements = "UVGHZZCDZZMZKNZZZYSAABWZR";
constexpr const char* complements = "UVGHZZCDZZMZKNZZZYSAABWZR";
return (symbol < 'A' || symbol >= 'Z') ? 'Z' : complements[symbol - 'A']; return (symbol < 'A' || symbol >= 'Z') ? 'Z' : complements[symbol - 'A'];
} }
} }

+ 67
- 105
src/geom/hyperoctree.hpp View File

@ -20,6 +20,8 @@
#ifndef ANTKEEPER_GEOM_HYPEROCTREE_HPP #ifndef ANTKEEPER_GEOM_HYPEROCTREE_HPP
#define ANTKEEPER_GEOM_HYPEROCTREE_HPP #define ANTKEEPER_GEOM_HYPEROCTREE_HPP
#include "math/compile.hpp"
#include <bit>
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
@ -31,9 +33,7 @@ namespace geom {
/** /**
* Hashed linear hyperoctree. * Hashed linear hyperoctree.
* *
* @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html
* @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/
*
* @tparam T Integer node type.
* @tparam N Number of dimensions. * @tparam N Number of dimensions.
* @tparam D Max depth. * @tparam D Max depth.
* *
@ -46,7 +46,6 @@ namespace geom {
* 64 bit ( 8 byte) = max depth 28 ( 58 loc bits, 5 depth bits, 1 divider bit) = 64 bits * 64 bit ( 8 byte) = max depth 28 ( 58 loc bits, 5 depth bits, 1 divider bit) = 64 bits
* 128 bit (16 byte) = max depth 59 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits * 128 bit (16 byte) = max depth 59 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
* 256 bit (32 byte) = max depth 123 (248 loc bits, 7 depth bits, 1 divider bit) = 256 bits * 256 bit (32 byte) = max depth 123 (248 loc bits, 7 depth bits, 1 divider bit) = 256 bits
*
* @see https://oeis.org/A173009 * @see https://oeis.org/A173009
* *
* 3D: * 3D:
@ -56,18 +55,14 @@ namespace geom {
* 64 bit ( 8 byte) = max depth 18 ( 57 loc bits, 5 depth bits, 1 divider bit) = 63 bits * 64 bit ( 8 byte) = max depth 18 ( 57 loc bits, 5 depth bits, 1 divider bit) = 63 bits
* 128 bit (16 byte) = max depth 39 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits * 128 bit (16 byte) = max depth 39 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
* 256 bit (32 byte) = max depth 81 (243 loc bits, 7 depth bits, 1 divider bit) = 251 bits * 256 bit (32 byte) = max depth 81 (243 loc bits, 7 depth bits, 1 divider bit) = 251 bits
*
* @see https://oeis.org/A178420 * @see https://oeis.org/A178420
* *
* @tparam T Integer node type.
* @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html
* @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/
*/ */
template <std::size_t N, std::size_t D, class T>
template <class T, std::size_t N, std::size_t D>
class hyperoctree class hyperoctree
{ {
private:
/// Compile-time calculation of the minimum bits required to represent `n` state changes.
static constexpr T ceil_log2(T n);
public: public:
/// Integral node type. /// Integral node type.
typedef T node_type; typedef T node_type;
@ -79,8 +74,8 @@ public:
static constexpr std::size_t max_depth = D; static constexpr std::size_t max_depth = D;
/// Number of bits required to encode the depth of a node. /// Number of bits required to encode the depth of a node.
static constexpr T depth_bits = ceil_log2(max_depth + 1);
static constexpr T depth_bits = math::compile::ceil_log2(max_depth + 1);
/// Number of bits required to encode the location of a node. /// Number of bits required to encode the location of a node.
static constexpr T location_bits = (max_depth + 1) * N; static constexpr T location_bits = (max_depth + 1) * N;
@ -89,7 +84,7 @@ public:
// Ensure the node type has enough bits // Ensure the node type has enough bits
static_assert(depth_bits + location_bits + 1 <= node_bits, "Size of hyperoctree node type is insufficient to encode the maximum depth"); static_assert(depth_bits + location_bits + 1 <= node_bits, "Size of hyperoctree node type is insufficient to encode the maximum depth");
/// Number of children per node. /// Number of children per node.
static constexpr T children_per_node = (N) ? (2 << (N - 1)) : 1; static constexpr T children_per_node = (N) ? (2 << (N - 1)) : 1;
@ -98,7 +93,7 @@ public:
/// Root node which is always guaranteed to exist. /// Root node which is always guaranteed to exist.
static constexpr node_type root = 0; static constexpr node_type root = 0;
/** /**
* Accesses nodes in their internal hashmap order. * Accesses nodes in their internal hashmap order.
*/ */
@ -116,7 +111,7 @@ public:
inline explicit unordered_iterator(const typename std::unordered_set<node_type>::const_iterator& it): set_iterator(it) {}; inline explicit unordered_iterator(const typename std::unordered_set<node_type>::const_iterator& it): set_iterator(it) {};
typename std::unordered_set<node_type>::const_iterator set_iterator; typename std::unordered_set<node_type>::const_iterator set_iterator;
}; };
/** /**
* Accesses nodes in z-order. * Accesses nodes in z-order.
* *
@ -136,7 +131,7 @@ public:
const hyperoctree* hyperoctree; const hyperoctree* hyperoctree;
std::stack<node_type> stack; std::stack<node_type> stack;
}; };
/** /**
* Returns the depth of a node. * Returns the depth of a node.
* *
@ -144,7 +139,7 @@ public:
* @return Depth of the node. * @return Depth of the node.
*/ */
static T depth(node_type node); static T depth(node_type node);
/** /**
* Returns the Morton code location of a node. * Returns the Morton code location of a node.
* *
@ -152,7 +147,7 @@ public:
* @return Morton code location of the node. * @return Morton code location of the node.
*/ */
static T location(node_type node); static T location(node_type node);
/** /**
* Returns the node at the given depth and location. * Returns the node at the given depth and location.
* *
@ -250,24 +245,24 @@ public:
/// Returns the number of nodes in the hyperoctree. /// Returns the number of nodes in the hyperoctree.
std::size_t size() const; std::size_t size() const;
/// Returns the total number of nodes the hyperoctree is capable of containing.
static consteval std::size_t max_size() noexcept
{
return (math::compile::pow<std::size_t>(children_per_node, max_depth + 1) - 1) / (children_per_node - 1);
}
private: private:
/// Compile-time pow()
static constexpr T pow(T x, T exponent);
/// Count leading zeros
static T clz(T x);
std::unordered_set<node_type> nodes; std::unordered_set<node_type> nodes;
}; };
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::iterator& hyperoctree<N, D, T>::iterator::operator++()
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::iterator& hyperoctree<T, N, D>::iterator::operator++()
{ {
// Get next node from top of stack // Get next node from top of stack
node_type node = stack.top(); node_type node = stack.top();
stack.pop(); stack.pop();
// If the node has children // If the node has children
if (!hyperoctree->is_leaf(node)) if (!hyperoctree->is_leaf(node))
{ {
@ -275,54 +270,48 @@ typename hyperoctree::iterator& hyperoctree::iterator::operato
for (T i = 0; i < children_per_node; ++i) for (T i = 0; i < children_per_node; ++i)
stack.push(child(node, siblings_per_node - i)); stack.push(child(node, siblings_per_node - i));
} }
if (stack.empty()) if (stack.empty())
stack.push(std::numeric_limits<T>::max()); stack.push(std::numeric_limits<T>::max());
return *this; return *this;
} }
template <std::size_t N, std::size_t D, class T>
constexpr T hyperoctree<N, D, T>::ceil_log2(T n)
{
return (n <= 1) ? 0 : ceil_log2((n + 1) / 2) + 1;
}
template <std::size_t N, std::size_t D, class T>
inline T hyperoctree<N, D, T>::depth(node_type node)
template <class T, std::size_t N, std::size_t D>
inline T hyperoctree<T, N, D>::depth(node_type node)
{ {
// Extract depth using a bit mask // Extract depth using a bit mask
constexpr T mask = pow(2, depth_bits) - 1;
constexpr T mask = math::compile::pow<node_type>(2, depth_bits) - 1;
return node & mask; return node & mask;
} }
template <std::size_t N, std::size_t D, class T>
inline T hyperoctree<N, D, T>::location(node_type node)
template <class T, std::size_t N, std::size_t D>
inline T hyperoctree<T, N, D>::location(node_type node)
{ {
return node >> ((node_bits - 1) - depth(node) * N); return node >> ((node_bits - 1) - depth(node) * N);
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::node(T depth, T location)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::node(T depth, T location)
{ {
return (location << ((node_bits - 1) - depth * N)) | depth; return (location << ((node_bits - 1) - depth * N)) | depth;
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::ancestor(node_type node, T depth)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::ancestor(node_type node, T depth)
{ {
const T mask = std::numeric_limits<T>::max() << ((node_bits - 1) - depth * N); const T mask = std::numeric_limits<T>::max() << ((node_bits - 1) - depth * N);
return (node & mask) | depth; return (node & mask) | depth;
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::parent(node_type node)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::parent(node_type node)
{ {
return ancestor(node, depth(node) - 1); return ancestor(node, depth(node) - 1);
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::sibling(node_type node, T n)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::sibling(node_type node, T n)
{ {
constexpr T mask = (1 << N) - 1; constexpr T mask = (1 << N) - 1;
@ -332,28 +321,28 @@ inline typename hyperoctree::node_type hyperoctree::sibling(no
return hyperoctree::node(depth, (location & (~mask)) | ((location + n) & mask)); return hyperoctree::node(depth, (location & (~mask)) | ((location + n) & mask));
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::child(node_type node, T n)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::child(node_type node, T n)
{ {
return sibling(node + 1, n); return sibling(node + 1, n);
} }
template <std::size_t N, std::size_t D, class T>
inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::common_ancestor(node_type a, node_type b)
template <class T, std::size_t N, std::size_t D>
inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::common_ancestor(node_type a, node_type b)
{ {
T bits = std::min<T>(depth(a), depth(b)) * N; T bits = std::min<T>(depth(a), depth(b)) * N;
T marker = (T(1) << (node_bits - 1)) >> bits; T marker = (T(1) << (node_bits - 1)) >> bits;
T depth = clz((a ^ b) | marker) / N;
T depth = T(std::countl_zero((a ^ b) | marker) / N);
return ancestor(a, depth); return ancestor(a, depth);
} }
template <std::size_t N, std::size_t D, class T>
inline hyperoctree<N, D, T>::hyperoctree():
template <class T, std::size_t N, std::size_t D>
inline hyperoctree<T, N, D>::hyperoctree():
nodes({0}) nodes({0})
{} {}
template <std::size_t N, std::size_t D, class T>
void hyperoctree<N, D, T>::insert(node_type node)
template <class T, std::size_t N, std::size_t D>
void hyperoctree<T, N, D>::insert(node_type node)
{ {
if (contains(node)) if (contains(node))
return; return;
@ -371,8 +360,8 @@ void hyperoctree::insert(node_type node)
insert(parent); insert(parent);
} }
template <std::size_t N, std::size_t D, class T>
void hyperoctree<N, D, T>::erase(node_type node)
template <class T, std::size_t N, std::size_t D>
void hyperoctree<T, N, D>::erase(node_type node)
{ {
// Don't erase the root! // Don't erase the root!
if (node == root) if (node == root)
@ -396,87 +385,60 @@ void hyperoctree::erase(node_type node)
} }
} }
template <std::size_t N, std::size_t D, class T>
void hyperoctree<N, D, T>::clear()
template <class T, std::size_t N, std::size_t D>
void hyperoctree<T, N, D>::clear()
{ {
nodes = {0}; nodes = {0};
} }
template <std::size_t N, std::size_t D, class T>
inline bool hyperoctree<N, D, T>::contains(node_type node) const
template <class T, std::size_t N, std::size_t D>
inline bool hyperoctree<T, N, D>::contains(node_type node) const
{ {
return nodes.count(node); return nodes.count(node);
} }
template <std::size_t N, std::size_t D, class T>
inline bool hyperoctree<N, D, T>::is_leaf(node_type node) const
template <class T, std::size_t N, std::size_t D>
inline bool hyperoctree<T, N, D>::is_leaf(node_type node) const
{ {
return !contains(child(node, 0)); return !contains(child(node, 0));
} }
template <std::size_t N, std::size_t D, class T>
inline std::size_t hyperoctree<N, D, T>::size() const
template <class T, std::size_t N, std::size_t D>
inline std::size_t hyperoctree<T, N, D>::size() const
{ {
return nodes.size(); return nodes.size();
} }
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::begin() const
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::begin() const
{ {
return iterator(this, hyperoctree::root); return iterator(this, hyperoctree::root);
} }
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::end() const
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::end() const
{ {
return iterator(this, std::numeric_limits<T>::max()); return iterator(this, std::numeric_limits<T>::max());
} }
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::find(node_type node) const
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::find(node_type node) const
{ {
return contains(node) ? iterator(node) : end(); return contains(node) ? iterator(node) : end();
} }
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::unordered_iterator hyperoctree<N, D, T>::unordered_begin() const
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::unordered_iterator hyperoctree<T, N, D>::unordered_begin() const
{ {
return unordered_iterator(nodes.begin()); return unordered_iterator(nodes.begin());
} }
template <std::size_t N, std::size_t D, class T>
typename hyperoctree<N, D, T>::unordered_iterator hyperoctree<N, D, T>::unordered_end() const
template <class T, std::size_t N, std::size_t D>
typename hyperoctree<T, N, D>::unordered_iterator hyperoctree<T, N, D>::unordered_end() const
{ {
return unordered_iterator(nodes.end()); return unordered_iterator(nodes.end());
} }
template <std::size_t N, std::size_t D, class T>
constexpr T hyperoctree<N, D, T>::pow(T x, T exponent)
{
return (exponent == 0) ? 1 : x * pow(x, exponent - 1);
}
template <std::size_t N, std::size_t D, class T>
T hyperoctree<N, D, T>::clz(T x)
{
if (!x)
return sizeof(T) * 8;
#if defined(__GNU__)
return __builtin_clz(x);
#else
T n = 0;
while ((x & (T(1) << (8 * sizeof(x) - 1))) == 0)
{
x <<= 1;
++n;
}
return n;
#endif
}
} // namespace geom } // namespace geom
#endif // ANTKEEPER_GEOM_HYPEROCTREE_HPP #endif // ANTKEEPER_GEOM_HYPEROCTREE_HPP

+ 6
- 6
src/geom/octree.hpp View File

@ -25,20 +25,20 @@
namespace geom { namespace geom {
/// An octree, or 3-dimensional hyperoctree. /// An octree, or 3-dimensional hyperoctree.
template <std::size_t D, class T>
using octree = hyperoctree<3, D, T>;
template <class T, std::size_t D>
using octree = hyperoctree<T, 3, D>;
/// Octree with an 8-bit node type (2 depth levels). /// Octree with an 8-bit node type (2 depth levels).
typedef octree<1, std::uint8_t> octree8;
typedef octree<std::uint8_t, 1> octree8;
/// Octree with a 16-bit node type (4 depth levels). /// Octree with a 16-bit node type (4 depth levels).
typedef octree<3, std::uint16_t> octree16;
typedef octree<std::uint16_t, 3> octree16;
/// Octree with a 32-bit node type (9 depth levels). /// Octree with a 32-bit node type (9 depth levels).
typedef octree<8, std::uint32_t> octree32;
typedef octree<std::uint32_t, 8> octree32;
/// Octree with a 64-bit node type (19 depth levels). /// Octree with a 64-bit node type (19 depth levels).
typedef octree<18, std::uint64_t> octree64;
typedef octree<std::uint64_t, 18> octree64;
} // namespace geom } // namespace geom

+ 6
- 6
src/geom/quadtree.hpp View File

@ -25,20 +25,20 @@
namespace geom { namespace geom {
/// A quadtree, or 2-dimensional hyperoctree. /// A quadtree, or 2-dimensional hyperoctree.
template <std::size_t D, class T>
using quadtree = hyperoctree<2, D, T>;
template <class T, std::size_t D>
using quadtree = hyperoctree<T, 2, D>;
/// Quadtree with an 8-bit node type (2 depth levels). /// Quadtree with an 8-bit node type (2 depth levels).
typedef quadtree<1, std::uint8_t> quadtree8;
typedef quadtree<std::uint8_t, 1> quadtree8;
/// Quadtree with a 16-bit node type (6 depth levels). /// Quadtree with a 16-bit node type (6 depth levels).
typedef quadtree<5, std::uint16_t> quadtree16;
typedef quadtree<std::uint16_t, 5> quadtree16;
/// Quadtree with a 32-bit node type (13 depth levels). /// Quadtree with a 32-bit node type (13 depth levels).
typedef quadtree<12, std::uint32_t> quadtree32;
typedef quadtree<std::uint32_t, 12> quadtree32;
/// Quadtree with a 64-bit node type (29 depth levels). /// Quadtree with a 64-bit node type (29 depth levels).
typedef quadtree<28, std::uint64_t> quadtree64;
typedef quadtree<std::uint64_t, 28> quadtree64;
} // namespace geom } // namespace geom

+ 61
- 0
src/math/compile.hpp View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_MATH_COMPILE_HPP
#define ANTKEEPER_MATH_COMPILE_HPP
#include <concepts>
namespace math {
/// Compile-time mathematical functions.
namespace compile {
/**
* Compile-time `pow` for unsigned integrals.
*
* @param x Base value.
* @param e Integral exponent.
*
* @return `x^e`.
*/
template <std::unsigned_integral T>
consteval T pow(T x, T e) noexcept
{
return (e == 0) ? T(1) : (x * pow<T>(x, e - 1));
}
/**
* Compile-time `ceil(log2(x))` for unsigned integrals.
*
* @param x Input value.
*
* @return `ceil(log2(x))`.
*/
template <std::unsigned_integral T>
consteval T ceil_log2(T x) noexcept
{
return (x <= T(1)) ? T(0) : ceil_log2((x + T(1)) / T(2)) + T(1);
}
} // namespace compile
} // namespace math
#endif // ANTKEEPER_MATH_COMPILE_HPP

+ 2
- 2
src/math/matrix.hpp View File

@ -123,11 +123,11 @@ struct matrix
/// @{ /// @{
constexpr inline column_vector_type& back() noexcept constexpr inline column_vector_type& back() noexcept
{ {
return elements[column_count - 1];
return columns[column_count - 1];
} }
constexpr inline const column_vector_type& back() const noexcept constexpr inline const column_vector_type& back() const noexcept
{ {
return elements[column_count - 1];
return columns[column_count - 1];
} }
/// @} /// @}

+ 1
- 1
src/math/transform-type.hpp View File

@ -47,7 +47,7 @@ struct transform
}; };
template <class T> template <class T>
constexpr transform<T> transform<T>::identity =
const transform<T> transform<T>::identity =
{ {
vector<T, 3>::zero(), vector<T, 3>::zero(),
quaternion<T>::identity(), quaternion<T>::identity(),

+ 4
- 4
src/math/vector.hpp View File

@ -633,7 +633,7 @@ vector normalize(const vector& x);
* @return Logically inverted vector. * @return Logically inverted vector.
*/ */
template <class T, std::size_t N> template <class T, std::size_t N>
constexpr vector<bool, N> not(const vector<T, N>& x) noexcept;
constexpr vector<bool, N> logical_not(const vector<T, N>& x) noexcept;
/** /**
* Compares two vectors for inequality * Compares two vectors for inequality
@ -1189,15 +1189,15 @@ inline vector normalize(const vector& x)
/// @private /// @private
template <class T, std::size_t N, std::size_t... I> template <class T, std::size_t N, std::size_t... I>
constexpr inline vector<bool, N> not(const vector<T, N>& x, std::index_sequence<I...>) noexcept
constexpr inline vector<bool, N> logical_not(const vector<T, N>& x, std::index_sequence<I...>) noexcept
{ {
return {!x[I]...}; return {!x[I]...};
} }
template <class T, std::size_t N> template <class T, std::size_t N>
constexpr inline vector<bool, N> not(const vector<T, N>& x) noexcept
constexpr inline vector<bool, N> logical_not(const vector<T, N>& x) noexcept
{ {
return not(x, std::make_index_sequence<N>{});
return logical_not(x, std::make_index_sequence<N>{});
} }
/// @private /// @private

+ 3
- 1
src/resources/behavior-tree-loader.cpp View File

@ -29,6 +29,8 @@
#include <sstream> #include <sstream>
#include <physfs.h> #include <physfs.h>
/*
template <class T> template <class T>
void parse_argument(T& value, const std::string& string) void parse_argument(T& value, const std::string& string)
{ {
@ -160,4 +162,4 @@ entity::ebt::node* resource_loader::load(resource_manager* re
return load_node(json.cbegin(), resource_manager); return load_node(json.cbegin(), resource_manager);
} }
*/

+ 4
- 2
src/resources/entity-archetype-loader.cpp View File

@ -87,6 +87,7 @@ static bool load_component_atmosphere(entity::archetype& archetype, const json&
return true; return true;
} }
/*
static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element) static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
{ {
game::component::behavior component; game::component::behavior component;
@ -107,6 +108,7 @@ static bool load_component_behavior(entity::archetype& archetype, resource_manag
return (component.behavior_tree != nullptr); return (component.behavior_tree != nullptr);
} }
*/
static bool load_component_blackbody(entity::archetype& archetype, const json& element) static bool load_component_blackbody(entity::archetype& archetype, const json& element)
{ {
@ -306,8 +308,8 @@ static bool load_component(entity::archetype& archetype, resource_manager& resou
{ {
if (element.key() == "atmosphere") if (element.key() == "atmosphere")
return load_component_atmosphere(archetype, element.value()); return load_component_atmosphere(archetype, element.value());
if (element.key() == "behavior")
return load_component_behavior(archetype, resource_manager, element.value());
// if (element.key() == "behavior")
// return load_component_behavior(archetype, resource_manager, element.value());
if (element.key() == "blackbody") if (element.key() == "blackbody")
return load_component_blackbody(archetype, element.value()); return load_component_blackbody(archetype, element.value());
if (element.key() == "celestial_body") if (element.key() == "celestial_body")

+ 1
- 1
src/resources/resource-manager.hpp View File

@ -225,7 +225,7 @@ void resource_manager::save(const T* resource, const std::filesystem::path& path
status = EXIT_FAILURE; status = EXIT_FAILURE;
} }
logger->pop_task(status)
logger->pop_task(status);
} }
inline entt::registry& resource_manager::get_archetype_registry() inline entt::registry& resource_manager::get_archetype_registry()

Loading…
Cancel
Save