@ -0,0 +1,94 @@ | |||
/* | |||
* Copyright (C) 2023 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_EVENT_DISPATCHER_HPP | |||
#define ANTKEEPER_EVENT_DISPATCHER_HPP | |||
#include <engine/event/subscriber.hpp> | |||
#include <engine/event/subscription.hpp> | |||
#include <any> | |||
#include <map> | |||
#include <memory> | |||
#include <typeindex> | |||
#include <utility> | |||
namespace event { | |||
/** | |||
* Forwards messages from publishers to subscribers. | |||
*/ | |||
class dispatcher | |||
{ | |||
public: | |||
/** | |||
* Subscribes a function object to messages dispatched by this dispatcher. | |||
* | |||
* @tparam T Message type. | |||
* | |||
* @param subscriber Function object to subscribe. | |||
* | |||
* @return Shared subscription object which will unsubscribe the subscriber on destruction. | |||
* | |||
*/ | |||
template <class T> | |||
[[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber) | |||
{ | |||
// Allocate shared pointer to std::any object containing subscriber | |||
std::shared_ptr<std::any> shared_subscriber = std::make_shared<std::any>(std::make_any<event::subscriber<T>>(std::move(subscriber))); | |||
// Append subscriber to subscriber list and store iterator | |||
auto iterator = subscribers.emplace(std::type_index(typeid(T)), shared_subscriber); | |||
// Construct and return a shared subscription object which removes the subscriber from the subscriber list when unsubscribed or destructed | |||
return std::make_shared<subscription> | |||
( | |||
std::static_pointer_cast<void>(shared_subscriber), | |||
[this, iterator = std::move(iterator)]() | |||
{ | |||
this->subscribers.erase(iterator); | |||
} | |||
); | |||
} | |||
/** | |||
* Dispatches a message to subscribers of the message type. | |||
* | |||
* @tparam T Message type. | |||
* | |||
* @param message Message to dispatch. | |||
*/ | |||
template <class T> | |||
void dispatch(const T& message) const | |||
{ | |||
// For each subscriber of the given message type | |||
const auto range = subscribers.equal_range(std::type_index(typeid(T))); | |||
for (auto i = range.first; i != range.second; ++i) | |||
{ | |||
// Send message to subscriber | |||
std::any_cast<subscriber<T>>(*(i->second))(message); | |||
} | |||
} | |||
private: | |||
std::multimap<std::type_index, std::shared_ptr<std::any>> subscribers; | |||
}; | |||
} // namespace event | |||
#endif // ANTKEEPER_EVENT_DISPATCHER_HPP |
@ -0,0 +1,149 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_COLLIDER_MATERIAL_HPP | |||
#define ANTKEEPER_PHYSICS_COLLIDER_MATERIAL_HPP | |||
#include <engine/physics/kinematics/friction-combine-mode.hpp> | |||
#include <engine/physics/kinematics/restitution-combine-mode.hpp> | |||
namespace physics { | |||
/** | |||
* Describes the collision response of a collider. | |||
*/ | |||
class collider_material | |||
{ | |||
public: | |||
/** | |||
* Constructs a collider material. | |||
* | |||
* @param restitution Restitution value. | |||
* @param static_friction Static friction value. | |||
* @param dynamic_friction Dynamic friction value. | |||
*/ | |||
/// @{ | |||
inline collider_material(float restitution, float static_friction, float dynamic_friction) noexcept: | |||
m_restitution{restitution}, | |||
m_static_friction{static_friction}, | |||
m_dynamic_friction{dynamic_friction} | |||
{} | |||
collider_material() noexcept = default; | |||
/// @} | |||
/** | |||
* Sets the of restitution of the material. | |||
* | |||
* @param restitution Restitution value. | |||
*/ | |||
inline void set_restitution(float restitution) noexcept | |||
{ | |||
m_restitution = restitution; | |||
} | |||
/** | |||
* Sets the static friction of the material. | |||
* | |||
* @param friction Static friction value. | |||
*/ | |||
inline void set_static_friction(float friction) noexcept | |||
{ | |||
m_static_friction = friction; | |||
} | |||
/** | |||
* Sets the dynamic friction of the material. | |||
* | |||
* @param friction Dynamic friction value. | |||
*/ | |||
inline void set_dynamic_friction(float friction) noexcept | |||
{ | |||
m_dynamic_friction = friction; | |||
} | |||
/** | |||
* Sets the restitution combine mode of the material. | |||
* | |||
* @param mode Restitution combine mode. | |||
*/ | |||
inline void set_restitution_combine_mode(restitution_combine_mode mode) noexcept | |||
{ | |||
m_restitution_combine_mode = mode; | |||
} | |||
/** | |||
* Sets the friction combine mode of the material. | |||
* | |||
* @param mode Friction combine mode. | |||
*/ | |||
inline void set_friction_combine_mode(friction_combine_mode mode) noexcept | |||
{ | |||
m_friction_combine_mode = mode; | |||
} | |||
/// Returns the restitution of the material. | |||
[[nodiscard]] inline float get_restitution() const noexcept | |||
{ | |||
return m_restitution; | |||
} | |||
/// Returns the static friction of the material. | |||
[[nodiscard]] inline float get_static_friction() const noexcept | |||
{ | |||
return m_static_friction; | |||
} | |||
/// Returns the dynamic friction of the material. | |||
[[nodiscard]] inline float get_dynamic_friction() const noexcept | |||
{ | |||
return m_dynamic_friction; | |||
} | |||
/// Returns the restitution combine mode. | |||
[[nodiscard]] inline restitution_combine_mode get_restitution_combine_mode() const noexcept | |||
{ | |||
return m_restitution_combine_mode; | |||
} | |||
/// Returns the friction combine mode. | |||
[[nodiscard]] inline friction_combine_mode get_friction_combine_mode() const noexcept | |||
{ | |||
return m_friction_combine_mode; | |||
} | |||
private: | |||
/// Restitution value. | |||
float m_restitution{0.0f}; | |||
/// Static friction value. | |||
float m_static_friction{0.0f}; | |||
/// Dynamic friction value. | |||
float m_dynamic_friction{0.0f}; | |||
/// Restitution combine mode. | |||
restitution_combine_mode m_restitution_combine_mode{restitution_combine_mode::average}; | |||
/// Friction combine mode. | |||
friction_combine_mode m_friction_combine_mode{friction_combine_mode::average}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_COLLIDER_MATERIAL_HPP |
@ -0,0 +1,44 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_COLLIDER_TYPE_HPP | |||
#define ANTKEEPER_PHYSICS_COLLIDER_TYPE_HPP | |||
#include <cstdint> | |||
namespace physics { | |||
/** | |||
* Collider types. | |||
*/ | |||
enum class collider_type: std::uint8_t | |||
{ | |||
/// Plane collider. | |||
plane, | |||
/// Sphere collider. | |||
sphere, | |||
/// Box collider. | |||
box | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_COLLIDER_TYPE_HPP |
@ -0,0 +1,81 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_COLLIDER_HPP | |||
#define ANTKEEPER_PHYSICS_COLLIDER_HPP | |||
#include <engine/physics/kinematics/collider-type.hpp> | |||
#include <engine/physics/kinematics/collider-material.hpp> | |||
#include <cstdint> | |||
#include <memory> | |||
namespace physics { | |||
/** | |||
* Abstract base class for collision objects. | |||
*/ | |||
class collider | |||
{ | |||
public: | |||
/** | |||
* Returns the collider type. | |||
*/ | |||
[[nodiscard]] virtual constexpr collider_type type() const noexcept = 0; | |||
/** | |||
* Sets the layer mask of the collider. | |||
* | |||
* @param mask 32-bit layer mask in which each bit represents a layer with which the collider can interact. | |||
*/ | |||
inline void set_layer_mask(std::uint32_t mask) noexcept | |||
{ | |||
m_layer_mask = mask; | |||
} | |||
/** | |||
* Sets the collider material. | |||
*/ | |||
inline void set_material(std::shared_ptr<collider_material> material) noexcept | |||
{ | |||
m_material = material; | |||
} | |||
/// Returns the layer mask of the collider. | |||
[[nodiscard]] inline std::uint32_t get_layer_mask() const noexcept | |||
{ | |||
return m_layer_mask; | |||
} | |||
/// Returns the collider material. | |||
[[nodiscard]] inline const std::shared_ptr<collider_material>& get_material() const noexcept | |||
{ | |||
return m_material; | |||
} | |||
private: | |||
/// Layer mask, in which each bit represents a layer with which the rigid body can interact. | |||
std::uint32_t m_layer_mask{1}; | |||
/// Collider material. | |||
std::shared_ptr<collider_material> m_material; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_COLLIDER_HPP |
@ -0,0 +1,118 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_BOX_COLLIDER_HPP | |||
#define ANTKEEPER_PHYSICS_BOX_COLLIDER_HPP | |||
#include <engine/physics/kinematics/collider.hpp> | |||
#include <engine/geom/primitives/box.hpp> | |||
namespace physics { | |||
/** | |||
* Box collision object. | |||
*/ | |||
class box_collider: public collider | |||
{ | |||
public: | |||
/// Box type. | |||
using box_type = geom::primitive::box<float>; | |||
[[nodiscard]] inline constexpr collider_type type() const noexcept override | |||
{ | |||
return collider_type::box; | |||
} | |||
/** | |||
* Constructs a box collider from a box. | |||
* | |||
* @param box Box shape. | |||
*/ | |||
inline explicit box_collider(const box_type& box) noexcept: | |||
m_box{box} | |||
{} | |||
/** | |||
* Constructs a box collider. | |||
* | |||
* @param min Minimum extent of the box, in object space. | |||
* @param max Maximum extent of the box, in object space. | |||
*/ | |||
/// @{ | |||
inline box_collider(const math::vector<float, 3>& min, const math::vector<float, 3>& max) noexcept: | |||
m_box{min, max} | |||
{} | |||
box_collider() noexcept = default; | |||
/// @} | |||
/** | |||
* Sets the collider's box. | |||
* | |||
* @param box Box shape. | |||
*/ | |||
inline void set_box(const box_type& box) noexcept | |||
{ | |||
m_box = box; | |||
} | |||
/** | |||
* Sets the minimum extent of the box. | |||
* | |||
* @param min Minimum extent of the box, in object space. | |||
*/ | |||
inline void set_min(const math::vector<float, 3>& min) noexcept | |||
{ | |||
m_box.min = min; | |||
} | |||
/** | |||
* Sets the maximum extent of the box. | |||
* | |||
* @param max Maximum extent of the box, in object space. | |||
*/ | |||
inline void set_max(const math::vector<float, 3>& max) noexcept | |||
{ | |||
m_box.max = max; | |||
} | |||
/// Returns the box shape. | |||
[[nodiscard]] inline const box_type& get_box() const noexcept | |||
{ | |||
return m_box; | |||
} | |||
/// Returns the minimum extent of the box, in object space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_min() const noexcept | |||
{ | |||
return m_box.min; | |||
} | |||
/// Returns the maximum extent of the box, in object space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_max() const noexcept | |||
{ | |||
return m_box.max; | |||
} | |||
private: | |||
box_type m_box{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_BOX_COLLIDER_HPP |
@ -0,0 +1,131 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_PLANE_COLLIDER_HPP | |||
#define ANTKEEPER_PHYSICS_PLANE_COLLIDER_HPP | |||
#include <engine/physics/kinematics/collider.hpp> | |||
#include <engine/geom/primitives/plane.hpp> | |||
namespace physics { | |||
/** | |||
* Plane collision object. | |||
*/ | |||
class plane_collider: public collider | |||
{ | |||
public: | |||
/// Plane type. | |||
using plane_type = geom::primitive::plane<float>; | |||
[[nodiscard]] inline constexpr collider_type type() const noexcept override | |||
{ | |||
return collider_type::plane; | |||
} | |||
/** | |||
* Constructs a plane collider from a plane. | |||
* | |||
* @param plane Plane shape. | |||
*/ | |||
inline explicit plane_collider(const plane_type& plane) noexcept: | |||
m_plane{plane} | |||
{} | |||
/** | |||
* Constructs a plane collider from a normal and constant. | |||
* | |||
* @param normal Plane normal, in object space. | |||
* @param constant Plane constant. | |||
*/ | |||
/// @{ | |||
inline plane_collider(const math::vector<float, 3>& normal, float constant) noexcept: | |||
m_plane{normal, constant} | |||
{} | |||
inline explicit plane_collider(const math::vector<float, 3>& normal) noexcept: | |||
m_plane{normal, 0.0f} | |||
{} | |||
plane_collider() noexcept = default; | |||
/// @} | |||
/** | |||
* Constructs a plane collider from a normal and offset. | |||
* | |||
* @param normal Plane normal, in object space. | |||
* @param offset Offset from the origin, in object space. | |||
*/ | |||
inline plane_collider(const math::vector<float, 3>& normal, const math::vector<float, 3>& offset) noexcept: | |||
m_plane(normal, offset) | |||
{} | |||
/** | |||
* Sets the collider's plane. | |||
* | |||
* @param plane Plane shape. | |||
*/ | |||
inline void set_plane(const plane_type& plane) noexcept | |||
{ | |||
m_plane = plane; | |||
} | |||
/** | |||
* Sets the plane normal. | |||
* | |||
* @param normal Plane normal, in object space. | |||
*/ | |||
inline void set_normal(const math::vector<float, 3>& normal) noexcept | |||
{ | |||
m_plane.normal = normal; | |||
} | |||
/** | |||
* Sets the plane constant. | |||
* | |||
* @param constant Plane constant. | |||
*/ | |||
inline void set_constant(float constant) noexcept | |||
{ | |||
m_plane.constant = constant; | |||
} | |||
/// Returns the plane shape. | |||
[[nodiscard]] inline const plane_type& get_plane() const noexcept | |||
{ | |||
return m_plane; | |||
} | |||
/// Returns the plane normal, in object space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_normal() const noexcept | |||
{ | |||
return m_plane.normal; | |||
} | |||
/// Returns the plane constant. | |||
[[nodiscard]] inline float get_constant() const noexcept | |||
{ | |||
return m_plane.constant; | |||
} | |||
private: | |||
plane_type m_plane{{0.0f, 0.0f, 0.0f}, 0.0f}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_PLANE_COLLIDER_HPP |
@ -0,0 +1,121 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_SPHERE_COLLIDER_HPP | |||
#define ANTKEEPER_PHYSICS_SPHERE_COLLIDER_HPP | |||
#include <engine/physics/kinematics/collider.hpp> | |||
#include <engine/geom/primitives/sphere.hpp> | |||
namespace physics { | |||
/** | |||
* Sphere collision object. | |||
*/ | |||
class sphere_collider: public collider | |||
{ | |||
public: | |||
/// Sphere type. | |||
using sphere_type = geom::primitive::sphere<float>; | |||
[[nodiscard]] inline constexpr collider_type type() const noexcept override | |||
{ | |||
return collider_type::sphere; | |||
} | |||
/** | |||
* Constructs a sphere collider from a sphere. | |||
* | |||
* @param sphere Sphere shape. | |||
*/ | |||
inline explicit sphere_collider(const sphere_type& sphere) noexcept: | |||
m_sphere{sphere} | |||
{} | |||
/** | |||
* Constructs a sphere collider. | |||
* | |||
* @param center Sphere center. | |||
* @param radius Sphere radius. | |||
*/ | |||
/// @{ | |||
inline sphere_collider(const math::vector<float, 3>& center, float radius) noexcept: | |||
m_sphere{center, radius} | |||
{} | |||
inline explicit sphere_collider(float radius) noexcept: | |||
m_sphere{{0.0f, 0.0f, 0.0f}, radius} | |||
{} | |||
sphere_collider() noexcept = default; | |||
/// @} | |||
/** | |||
* Sets the collider's sphere. | |||
* | |||
* @param sphere Sphere shape. | |||
*/ | |||
inline void set_sphere(const sphere_type& sphere) noexcept | |||
{ | |||
m_sphere = sphere; | |||
} | |||
/** | |||
* Sets the center of the sphere. | |||
* | |||
* @param center Sphere center, in object space. | |||
*/ | |||
inline void set_center(const math::vector<float, 3>& center) noexcept | |||
{ | |||
m_sphere.center = center; | |||
} | |||
/** | |||
* Sets the radius of the sphere. | |||
* | |||
* @param radius Sphere radius. | |||
*/ | |||
inline void set_radius(float radius) noexcept | |||
{ | |||
m_sphere.radius = radius; | |||
} | |||
/// Returns the sphere shape. | |||
[[nodiscard]] inline const sphere_type& get_sphere() const noexcept | |||
{ | |||
return m_sphere; | |||
} | |||
/// Returns the center of the sphere, in object space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_center() const noexcept | |||
{ | |||
return m_sphere.center; | |||
} | |||
/// Returns the radius of the sphere. | |||
[[nodiscard]] inline float get_radius() const noexcept | |||
{ | |||
return m_sphere.radius; | |||
} | |||
private: | |||
sphere_type m_sphere{{0.0f, 0.0f, 0.0f}, 0.0f}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_SPHERE_COLLIDER_HPP |
@ -0,0 +1,53 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_COLLISION_MANIFOLD_HPP | |||
#define ANTKEEPER_PHYSICS_COLLISION_MANIFOLD_HPP | |||
#include <engine/physics/kinematics/collision-contact.hpp> | |||
#include <engine/physics/kinematics/rigid-body.hpp> | |||
#include <array> | |||
#include <cstdlib> | |||
namespace physics { | |||
/** | |||
* Collection of contact points between two colliding bodies. | |||
* | |||
* @param N Maximum number of contact points. | |||
*/ | |||
template <std::uint8_t N> | |||
struct collision_manifold | |||
{ | |||
/// First colliding body. | |||
rigid_body* body_a{nullptr}; | |||
/// Second colliding body. | |||
rigid_body* body_b{nullptr}; | |||
/// Set of contact points between body a and body b. | |||
std::array<collision_contact, N> contacts; | |||
/// Number of contact points between body a and body b. | |||
std::uint8_t contact_count{0}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_COLLISION_MANIFOLD_HPP |
@ -0,0 +1,41 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_CONSTRAINT_HPP | |||
#define ANTKEEPER_PHYSICS_CONSTRAINT_HPP | |||
namespace physics { | |||
/** | |||
* Abstract base class for rigid body constraints. | |||
*/ | |||
class constraint | |||
{ | |||
public: | |||
/** | |||
* Solves the constraint. | |||
* | |||
* @param dt Timestep, in seconds. | |||
*/ | |||
virtual void solve(float dt) = 0; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_CONSTRAINT_HPP |
@ -0,0 +1,53 @@ | |||
/* | |||
* Copyright (C) 2023 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/>. | |||
*/ | |||
#include <engine/physics/kinematics/constraints/spring-constraint.hpp> | |||
namespace physics { | |||
void spring_constraint::solve(float dt) | |||
{ | |||
if (!m_body_a || !m_body_b) | |||
{ | |||
return; | |||
} | |||
// Get radius vectors from centers of mass to spring attachment points | |||
const math::vector<float, 3> radius_a = m_body_a->get_orientation() * m_point_a; | |||
const math::vector<float, 3> radius_b = m_body_b->get_orientation() * m_point_b; | |||
// Get world-space spring attachment points | |||
const math::vector<float, 3> point_a = m_body_a->get_center_of_mass() + radius_a; | |||
const math::vector<float, 3> point_b = m_body_b->get_center_of_mass() + radius_b; | |||
// Calculate relative velocity between the attachment points | |||
const math::vector<float, 3> velocity = m_body_b->get_point_velocity(radius_b) - m_body_a->get_point_velocity(radius_a); | |||
// Calculate spring force | |||
// F = -k * (|x| - d) * (x / |x|) - bv | |||
const math::vector<float, 3> difference = point_b - point_a; | |||
const float distance = std::sqrt(math::dot(difference, difference)); | |||
const math::vector<float, 3> force = -m_stiffness * (distance - m_resting_length) * (difference / distance) - velocity * m_damping; | |||
// Apply spring force to bodies at attachment points | |||
m_body_a->apply_force(-force, radius_a); | |||
m_body_b->apply_force(force, radius_b); | |||
} | |||
} // namespace physics |
@ -0,0 +1,183 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_SPRING_CONSTRAINT_HPP | |||
#define ANTKEEPER_PHYSICS_SPRING_CONSTRAINT_HPP | |||
#include <engine/physics/kinematics/constraint.hpp> | |||
#include <engine/physics/kinematics/rigid-body.hpp> | |||
#include <engine/math/vector.hpp> | |||
namespace physics { | |||
/** | |||
* Spring constraint. | |||
*/ | |||
class spring_constraint: public constraint | |||
{ | |||
public: | |||
void solve(float dt) override; | |||
/** | |||
* Attaches the spring to body a. | |||
* | |||
* @param body_a Body to which the spring should be attached. | |||
* @param point_a Point on body a, in body-space, at which the spring should be attached. | |||
*/ | |||
inline void attach_a(rigid_body& body_a, const math::vector<float, 3>& point_a) noexcept | |||
{ | |||
m_body_a = &body_a; | |||
m_point_a = point_a; | |||
} | |||
/** | |||
* Attaches the spring to body b. | |||
* | |||
* @param body_b Body to which the spring should be attached. | |||
* @param point_b Point on body b, in body-space, at which the spring should be attached. | |||
*/ | |||
inline void attach_b(rigid_body& body_b, const math::vector<float, 3>& point_b) noexcept | |||
{ | |||
m_body_b = &body_b; | |||
m_point_b = point_b; | |||
} | |||
/** | |||
* Detaches the spring from body a. | |||
*/ | |||
inline void detach_a() noexcept | |||
{ | |||
m_body_a = nullptr; | |||
} | |||
/** | |||
* Detaches the spring from body b. | |||
*/ | |||
inline void detach_b() noexcept | |||
{ | |||
m_body_b = nullptr; | |||
} | |||
/** | |||
* Detaches the spring from bodies a and b. | |||
*/ | |||
inline void detach() noexcept | |||
{ | |||
detach_a(); | |||
detach_b(); | |||
} | |||
/** | |||
* Sets the resting length of the spring. | |||
* | |||
* @param length Resting length, in meters. | |||
*/ | |||
inline void set_resting_length(float length) noexcept | |||
{ | |||
m_resting_length = length; | |||
} | |||
/** | |||
* Sets the stiffness constant of the spring. | |||
* | |||
* @param stiffness Stiffness constant. | |||
*/ | |||
inline void set_stiffness(float stiffness) noexcept | |||
{ | |||
m_stiffness = stiffness; | |||
} | |||
/** | |||
* Sets the damping constant of the spring. | |||
* | |||
* @param damping Damping constant. | |||
*/ | |||
inline void set_damping(float damping) noexcept | |||
{ | |||
m_damping = damping; | |||
} | |||
/// Returns the body to which the spring is attached at point a. | |||
[[nodiscard]] inline rigid_body* get_body_a() const noexcept | |||
{ | |||
return m_body_a; | |||
} | |||
/// Returns the body to which the spring is attached at point b. | |||
[[nodiscard]] inline rigid_body* get_body_b() const noexcept | |||
{ | |||
return m_body_b; | |||
} | |||
/// Returns the point at which the spring is attached to body a, in body-space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_point_a() const noexcept | |||
{ | |||
return m_point_a; | |||
} | |||
/// Returns the point at which the spring is attached to body b, in body-space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_point_b() const noexcept | |||
{ | |||
return m_point_b; | |||
} | |||
/// Returns the resting length of the spring, in meters. | |||
[[nodiscard]] inline float get_resting_length() const noexcept | |||
{ | |||
return m_resting_length; | |||
} | |||
/// Returns the stiffness constant of the spring. | |||
[[nodiscard]] inline float get_stiffness() const noexcept | |||
{ | |||
return m_stiffness; | |||
} | |||
/// Returns the damping constant of the spring. | |||
[[nodiscard]] inline float get_damping() const noexcept | |||
{ | |||
return m_damping; | |||
} | |||
private: | |||
/// Rigid body to which the spring is attached at point a. | |||
rigid_body* m_body_a{nullptr}; | |||
/// Rigid body to which the spring is attached at point b. | |||
rigid_body* m_body_b{nullptr}; | |||
/// Point at which the spring is attached to body a, in body-space. | |||
math::vector<float, 3> m_point_a{0.0f, 0.0f, 0.0f}; | |||
/// Point at which the spring is attached to body b, in body-space. | |||
math::vector<float, 3> m_point_b{0.0f, 0.0f, 0.0f}; | |||
/// Resting length of the spring, in meters. | |||
float m_resting_length{0.0f}; | |||
/// Stiffness constant of the spring. | |||
float m_stiffness{1.0f}; | |||
/// Damping constant of the spring. | |||
float m_damping{1.0f}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_SPRING_CONSTRAINT_HPP |
@ -0,0 +1,63 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_FRICTION_COMBINE_MODE_HPP | |||
#define ANTKEEPER_PHYSICS_FRICTION_COMBINE_MODE_HPP | |||
#include <cstdint> | |||
namespace physics { | |||
/** | |||
* Specifies how coefficients of friction should be calculated. | |||
* | |||
* A coefficient of friction is calculated from two collider material friction values (`a` and `b`). | |||
*/ | |||
enum class friction_combine_mode: std::uint8_t | |||
{ | |||
/** | |||
* Coefficient of friction is calculated as `(a + b) / 2`. | |||
*/ | |||
average, | |||
/** | |||
* Coefficient of friction is calculated as `min(a, b)`. | |||
* | |||
* @note Takes priority over friction_combine_mode::average | |||
*/ | |||
minimum, | |||
/* | |||
* Coefficient of friction is calculated as `a * b`. | |||
* | |||
* @note Takes priority over friction_combine_mode::average and friction_combine_mode::minimum. | |||
*/ | |||
multiply, | |||
/* | |||
* Coefficient of friction is calculated as `max(a, b)`. | |||
* | |||
* @note Takes priority over friction_combine_mode::average, friction_combine_mode::minimum, and friction_combine_mode::multiply. | |||
*/ | |||
maximum | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_FRICTION_COMBINE_MODE_HPP |
@ -0,0 +1,63 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_RESTITUTION_COMBINE_MODE_HPP | |||
#define ANTKEEPER_PHYSICS_RESTITUTION_COMBINE_MODE_HPP | |||
#include <cstdint> | |||
namespace physics { | |||
/** | |||
* Specifies how coefficients of restitution should be calculated. | |||
* | |||
* A coefficient of restitution is calculated from two collider material restitution values (`a` and `b`). | |||
*/ | |||
enum class restitution_combine_mode: std::uint8_t | |||
{ | |||
/** | |||
* Coefficient of restitution is calculated as `(a + b) / 2`. | |||
*/ | |||
average, | |||
/** | |||
* Coefficient of restitution is calculated as `min(a, b)`. | |||
* | |||
* @note Takes priority over restitution_combine_mode::average | |||
*/ | |||
minimum, | |||
/* | |||
* Coefficient of restitution is calculated as `a * b`. | |||
* | |||
* @note Takes priority over restitution_combine_mode::average and restitution_combine_mode::minimum. | |||
*/ | |||
multiply, | |||
/* | |||
* Coefficient of restitution is calculated as `max(a, b)`. | |||
* | |||
* @note Takes priority over restitution_combine_mode::average, restitution_combine_mode::minimum, and restitution_combine_mode::multiply. | |||
*/ | |||
maximum | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_RESTITUTION_COMBINE_MODE_HPP |
@ -0,0 +1,54 @@ | |||
/* | |||
* Copyright (C) 2023 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/>. | |||
*/ | |||
#include <engine/physics/kinematics/rigid-body.hpp> | |||
#include <algorithm> | |||
namespace physics { | |||
void rigid_body::integrate_forces(float dt) noexcept | |||
{ | |||
// Apply forces | |||
m_linear_momentum += m_applied_force * dt; | |||
m_angular_momentum += m_applied_torque * dt; | |||
// Apply damping | |||
m_linear_momentum *= std::max<float>(0.0f, 1.0f - m_linear_damping * dt); | |||
m_angular_momentum *= std::max<float>(0.0f, 1.0f - m_angular_damping * dt); | |||
// Update velocities | |||
m_linear_velocity = m_inverse_mass * m_linear_momentum; | |||
m_angular_velocity = m_inverse_inertia * m_angular_momentum; | |||
// Clear forces | |||
m_applied_force = math::vector<float, 3>::zero(); | |||
m_applied_torque = math::vector<float, 3>::zero(); | |||
} | |||
void rigid_body::integrate_velocities(float dt) noexcept | |||
{ | |||
// Update center of mass | |||
m_center_of_mass += m_linear_velocity * dt; | |||
// Update orientation | |||
const math::quaternion<float> spin = math::quaternion<float>{0.0f, m_angular_velocity * 0.5f} * m_orientation; | |||
m_orientation = math::normalize(m_orientation + spin * dt); | |||
} | |||
} // namespace physics |
@ -0,0 +1,417 @@ | |||
/* | |||
* Copyright (C) 2023 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_PHYSICS_RIGID_BODY_HPP | |||
#define ANTKEEPER_PHYSICS_RIGID_BODY_HPP | |||
#include <engine/math/vector.hpp> | |||
#include <engine/math/quaternion.hpp> | |||
#include <engine/physics/kinematics/collider.hpp> | |||
#include <memory> | |||
namespace physics { | |||
/** | |||
* Rigid body. | |||
*/ | |||
class rigid_body | |||
{ | |||
public: | |||
/** | |||
* Sets the center of mass of the rigid body. | |||
* | |||
* @param point World-space center of mass. | |||
*/ | |||
inline void set_center_of_mass(const math::vector<float, 3>& point) noexcept | |||
{ | |||
m_center_of_mass = point; | |||
} | |||
/** | |||
* Sets the world-space orientation of the rigid body. | |||
* | |||
* @param orientation World-space orientation. | |||
*/ | |||
inline void set_orientation(const math::quaternion<float>& orientation) noexcept | |||
{ | |||
m_orientation = orientation; | |||
} | |||
/** | |||
* Sets mass of the rigid body. | |||
* | |||
* @param mass Mass, in kg. | |||
*/ | |||
inline void set_mass(float mass) noexcept | |||
{ | |||
m_mass = mass; | |||
m_inverse_mass = (mass) ? 1.0f / mass : 0.0f; | |||
} | |||
/** | |||
* Sets the moment of inertia of the rigid body. | |||
* | |||
* @param inertia Moment of inertia, in kg⋅m^2. | |||
*/ | |||
inline void set_inertia(float inertia) noexcept | |||
{ | |||
m_inertia = inertia; | |||
m_inverse_inertia = (inertia) ? 1.0f / inertia : 0.0f; | |||
} | |||
/** | |||
* Sets the collider of the rigid body. | |||
* | |||
* @param collider Shared pointer to a collider. | |||
*/ | |||
inline void set_collider(std::shared_ptr<collider> collider) noexcept | |||
{ | |||
m_collider = collider; | |||
} | |||
/** | |||
* Sets the linear damping factor of the rigid body. | |||
* | |||
* @param damping Linear damping factor. | |||
*/ | |||
inline void set_linear_damping(float damping) noexcept | |||
{ | |||
m_linear_damping = damping; | |||
} | |||
/** | |||
* Sets the angular damping factor of the rigid body. | |||
* | |||
* @param damping Angular damping factor. | |||
*/ | |||
inline void set_angular_damping(float damping) noexcept | |||
{ | |||
m_angular_damping = damping; | |||
} | |||
/** | |||
* Sets the linear momentum of the rigid body. | |||
* | |||
* @param momentum Linear momentum, in kg⋅m/s. | |||
*/ | |||
inline void set_linear_momentum(const math::vector<float, 3>& momentum) noexcept | |||
{ | |||
m_linear_momentum = momentum; | |||
m_linear_velocity = m_inverse_mass * m_linear_momentum; | |||
} | |||
/** | |||
* Sets the angular momentum of the rigid body. | |||
* | |||
* @param momentum Angular momentum, in kg⋅m^2⋅s^-1. | |||
*/ | |||
inline void set_angular_momentum(const math::vector<float, 3>& momentum) noexcept | |||
{ | |||
m_angular_momentum = momentum; | |||
m_angular_velocity = m_inverse_inertia * m_angular_momentum; | |||
} | |||
/** | |||
* Sets the linear velocity of the rigid body. | |||
* | |||
* @param velocity Linear velocity, in m/s. | |||
*/ | |||
inline void set_linear_velocity(const math::vector<float, 3>& velocity) noexcept | |||
{ | |||
m_linear_velocity = velocity; | |||
m_linear_momentum = m_mass * m_linear_velocity; | |||
} | |||
/** | |||
* Sets the angular velocity of the rigid body. | |||
* | |||
* @param velocity Angular velocity, rad/s. | |||
*/ | |||
inline void set_angular_velocity(const math::vector<float, 3>& velocity) noexcept | |||
{ | |||
m_angular_velocity = velocity; | |||
m_angular_momentum = m_inertia * m_angular_velocity; | |||
} | |||
/// Returns the world-space center of mass of the rigid body. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_center_of_mass() const noexcept | |||
{ | |||
return m_center_of_mass; | |||
} | |||
/// Returns the world-space orientation of the rigid body. | |||
[[nodiscard]] inline const math::quaternion<float>& get_orientation() const noexcept | |||
{ | |||
return m_orientation; | |||
} | |||
/// Returns the mass of the rigid body, in kg. | |||
[[nodiscard]] inline float get_mass() const noexcept | |||
{ | |||
return m_mass; | |||
} | |||
/// Returns the inverse mass of the rigid body, in kg^-1. | |||
[[nodiscard]] inline float get_inverse_mass() const noexcept | |||
{ | |||
return m_inverse_mass; | |||
} | |||
/// Returns the moment of inertia of the rigid body, in kg⋅m^2. | |||
[[nodiscard]] inline float get_inertia() const noexcept | |||
{ | |||
return m_inertia; | |||
} | |||
/// Returns the inverse moment of inertia of the rigid body, in kg⋅m^2^-1. | |||
[[nodiscard]] inline float get_inverse_inertia() const noexcept | |||
{ | |||
return m_inverse_inertia; | |||
} | |||
/// Returns the linear damping factor of the rigid body. | |||
[[nodiscard]] inline float get_linear_damping() const noexcept | |||
{ | |||
return m_linear_damping; | |||
} | |||
/// Returns the angular damping factor of the rigid body. | |||
[[nodiscard]] inline float get_angular_damping() const noexcept | |||
{ | |||
return m_angular_damping; | |||
} | |||
/// Returns the collider of the rigid body. | |||
[[nodiscard]] inline const std::shared_ptr<collider>& get_collider() const noexcept | |||
{ | |||
return m_collider; | |||
} | |||
/// Returns the linear momentum of the rigid body, in kg⋅m/s. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_linear_momentum() const noexcept | |||
{ | |||
return m_linear_momentum; | |||
} | |||
/// Returns the angular momentum of the rigid body, in kg⋅m^2⋅s^-1. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_angular_momentum() const noexcept | |||
{ | |||
return m_angular_momentum; | |||
} | |||
/// Returns the linear velocity of the rigid body, in m/s. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_linear_velocity() const noexcept | |||
{ | |||
return m_linear_velocity; | |||
} | |||
/// Returns the angular velocity of the rigid body, in rad/s. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_angular_velocity() const noexcept | |||
{ | |||
return m_angular_velocity; | |||
} | |||
/// Returns the total pre-integrated force, in N. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_applied_force() const noexcept | |||
{ | |||
return m_applied_force; | |||
} | |||
/// Returns the total pre-integrated torque, in N⋅m. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_applied_torque() const noexcept | |||
{ | |||
return m_applied_torque; | |||
} | |||
/** | |||
* Calculates the total velocity at a point on the rigid body. | |||
* | |||
* @param radius Radius vector from the center of mass to the point at which the velocity should be calculated. | |||
* | |||
* @return Point velocity. | |||
*/ | |||
[[nodiscard]] inline math::vector<float, 3> get_point_velocity(const math::vector<float, 3>& radius) const noexcept | |||
{ | |||
return m_linear_velocity + math::cross(m_angular_velocity, radius); | |||
} | |||
/** | |||
* Returns `true` if the rigid body is static, `false` otherwise. | |||
*/ | |||
[[nodiscard]] inline bool is_static() const noexcept | |||
{ | |||
return (m_mass == 0.0f); | |||
} | |||
/** | |||
* Applies a force at a point on the rigid body. | |||
* | |||
* @param force Force to apply, in N. | |||
* @param radius Radius vector from the center of mass to the point at which the force should be applied. | |||
*/ | |||
inline void apply_force(const math::vector<float, 3>& force, const math::vector<float, 3>& radius) noexcept | |||
{ | |||
m_applied_force += force; | |||
m_applied_torque += math::cross(radius, force); | |||
} | |||
/** | |||
* Applies a force at the center of mass of the rigid body. | |||
* | |||
* @param force Force to apply, in N. | |||
*/ | |||
inline void apply_central_force(const math::vector<float, 3>& force) noexcept | |||
{ | |||
m_applied_force += force; | |||
} | |||
/** | |||
* Applies a torque to the rigid body. | |||
* | |||
* @param torque Torque to apply. | |||
*/ | |||
inline void apply_torque(const math::vector<float, 3>& torque) noexcept | |||
{ | |||
m_applied_torque += torque; | |||
} | |||
/** | |||
* Applies an impulse at a point on the rigid body. | |||
* | |||
* @param impulse Impulse to apply, in N⋅s. | |||
* @param radius Radius vector from the center of mass to the point at which the impulse should be applied. | |||
*/ | |||
inline void apply_impulse(const math::vector<float, 3>& impulse, const math::vector<float, 3>& radius) noexcept | |||
{ | |||
m_linear_momentum += impulse; | |||
m_angular_momentum += math::cross(radius, impulse); | |||
// Update velocities | |||
m_linear_velocity = m_inverse_mass * m_linear_momentum; | |||
m_angular_velocity = m_inverse_inertia * m_angular_momentum; | |||
} | |||
/** | |||
* Applies an impulse at the center of mass of the rigid body. | |||
* | |||
* @param impulse Impulse to apply, in N⋅s. | |||
*/ | |||
inline void apply_central_impulse(const math::vector<float, 3>& impulse) noexcept | |||
{ | |||
m_linear_momentum += impulse; | |||
// Update linear velocity | |||
m_linear_velocity = m_inverse_mass * m_linear_momentum; | |||
} | |||
/** | |||
* Applies a torque impulse to the rigid body. | |||
* | |||
* @param torque Torque impulse to apply. | |||
*/ | |||
inline void apply_torque_impulse(const math::vector<float, 3>& torque) noexcept | |||
{ | |||
m_angular_momentum += torque; | |||
// Update angular velocity | |||
m_angular_velocity = m_inverse_inertia * m_angular_momentum; | |||
} | |||
/// Clears all pre-integrated forces. | |||
inline void clear_applied_forces() noexcept | |||
{ | |||
m_applied_force = math::vector<float, 3>::zero(); | |||
m_applied_torque = math::vector<float, 3>::zero(); | |||
} | |||
/** | |||
* Integrates forces, updating the momentums and velocities of the rigid body. | |||
* | |||
* @param dt Timestep, in seconds. | |||
*/ | |||
void integrate_forces(float dt) noexcept; | |||
/** | |||
* Integrates velocities, updating the center of mass and orientation of the rigid body. | |||
* | |||
* @param dt Timestep, in seconds. | |||
*/ | |||
void integrate_velocities(float dt) noexcept; | |||
/** | |||
* Integrates forces and velocities. | |||
* | |||
* @param dt Timestep, in seconds. | |||
*/ | |||
inline void integrate(float dt) noexcept | |||
{ | |||
integrate_forces(dt); | |||
integrate_velocities(dt); | |||
} | |||
private: | |||
/// World-space center of mass. | |||
math::vector<float, 3> m_center_of_mass{math::vector<float, 3>::zero()}; | |||
/// World-space orientation. | |||
math::quaternion<float> m_orientation{math::quaternion<float>::identity()}; | |||
/// Mass, in kg. | |||
float m_mass{1.0f}; | |||
/// Inverse mass, in kg^-1. | |||
float m_inverse_mass{1.0f}; | |||
/// Moment of inertia, in kg⋅m^2. | |||
float m_inertia{1.0f}; | |||
/// Inverse moment of inertia, in kg⋅m^2^-1. | |||
float m_inverse_inertia{1.0f}; | |||
/// Linear damping factor. | |||
float m_linear_damping{0.0f}; | |||
/// Angular damping factor. | |||
float m_angular_damping{0.0f}; | |||
/// Collider object. | |||
std::shared_ptr<collider> m_collider; | |||
/// Linear momentum, in kg⋅m/s. | |||
math::vector<float, 3> m_linear_momentum{math::vector<float, 3>::zero()}; | |||
/// Angular momentum, in kg⋅m^2⋅s^-1. | |||
math::vector<float, 3> m_angular_momentum{math::vector<float, 3>::zero()}; | |||
/// Linear velocity, in m/s. | |||
math::vector<float, 3> m_linear_velocity{math::vector<float, 3>::zero()}; | |||
/// Angular velocity, in rad/s. | |||
math::vector<float, 3> m_angular_velocity{math::vector<float, 3>::zero()}; | |||
/// Applied force, in N. | |||
math::vector<float, 3> m_applied_force{math::vector<float, 3>::zero()}; | |||
/// Applied torque, in N⋅m. | |||
math::vector<float, 3> m_applied_torque{math::vector<float, 3>::zero()}; | |||
}; | |||
} // namespace physics | |||
#endif // ANTKEEPER_PHYSICS_RIGID_BODY_HPP |
@ -0,0 +1,83 @@ | |||
/* | |||
* Copyright (C) 2023 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/>. | |||
*/ | |||
#include <engine/utility/frame-scheduler.hpp> | |||
#include <algorithm> | |||
#include <thread> | |||
frame_scheduler::frame_scheduler() noexcept | |||
{ | |||
m_frame_start_time = clock_type::now(); | |||
} | |||
void frame_scheduler::tick() | |||
{ | |||
// Measure duration of previous frame | |||
m_frame_end_time = clock_type::now(); | |||
m_frame_duration = m_frame_end_time - m_frame_start_time; | |||
// Idle until the minimum frame duration has passed | |||
if (m_frame_duration < m_min_frame_duration) | |||
{ | |||
// Determine time to idle until | |||
const time_point_type idle_time = m_frame_end_time + m_min_frame_duration - m_frame_duration; | |||
// Idle | |||
do | |||
{ | |||
std::this_thread::yield(); | |||
m_frame_end_time = clock_type::now(); | |||
} | |||
while (m_frame_end_time < idle_time); | |||
// Measure duration of previous frame with idle | |||
m_frame_duration = m_frame_end_time - m_frame_start_time; | |||
} | |||
// Accumulate previous frame duration (with limit to prevent "spiral of death") | |||
m_accumulated_time += std::min<duration_type>(m_max_frame_duration, m_frame_duration); | |||
// Start measuring duration of next frame | |||
m_frame_start_time = m_frame_end_time; | |||
// Perform fixed-rate updates | |||
while (m_accumulated_time >= m_fixed_update_interval) | |||
{ | |||
m_fixed_update_callback(m_fixed_update_time, m_fixed_update_interval); | |||
m_fixed_update_time += m_fixed_update_interval; | |||
m_accumulated_time -= m_fixed_update_interval; | |||
} | |||
// Perform variable-rate update | |||
m_variable_update_callback(m_fixed_update_time + m_accumulated_time, m_fixed_update_interval, m_accumulated_time); | |||
} | |||
void frame_scheduler::refresh() noexcept | |||
{ | |||
m_accumulated_time = duration_type::zero(); | |||
m_frame_duration = duration_type::zero(); | |||
m_frame_start_time = clock_type::now(); | |||
} | |||
void frame_scheduler::reset() noexcept | |||
{ | |||
m_fixed_update_time = duration_type::zero(); | |||
refresh(); | |||
} |
@ -0,0 +1,211 @@ | |||
/* | |||
* Copyright (C) 2023 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_UTILITY_FRAME_SCHEDULER_HPP | |||
#define ANTKEEPER_UTILITY_FRAME_SCHEDULER_HPP | |||
#include <chrono> | |||
#include <functional> | |||
#include <type_traits> | |||
/** | |||
* Schedules fixed- and variable-rate updates. | |||
* | |||
* @see https://gafferongames.com/post/fix_your_timestep/ | |||
*/ | |||
class frame_scheduler | |||
{ | |||
public: | |||
/// Clock type is `std::chrono::high_resolution_clock` if steady, `std::chrono::steady_clock` otherwise. | |||
using clock_type = std::conditional | |||
< | |||
std::chrono::high_resolution_clock::is_steady, | |||
std::chrono::high_resolution_clock, std::chrono::steady_clock | |||
>::type; | |||
/// Duration type matches the clock's duration type. | |||
using duration_type = clock_type::duration; | |||
/// Time point type matches the clock's time point type. | |||
using time_point_type = clock_type::time_point; | |||
/** | |||
* Fixed-rate update callback function type. | |||
* | |||
* The first parameter is the elapsed time (`t`) and the second parameter is the fixed-rate update interval (`dt`). | |||
*/ | |||
using fixed_update_callback_type = std::function<void(duration_type, duration_type)>; | |||
/** | |||
* Variable-rate callback function type. | |||
* | |||
* The first parameter is the elapsed time (`t`), the second parameter is the fixed-rate update interval (`dt`), and the third parameter is the accumulated time since the previous fixed-rate update (`at`). | |||
* | |||
* @note The subframe interpolation factor (`alpha`) can be calculated as `at / dt`. | |||
*/ | |||
using variable_update_callback_type = std::function<void(duration_type, duration_type, duration_type)>; | |||
/// Constructs a frame scheduler and starts its frame timer. | |||
frame_scheduler() noexcept; | |||
/** | |||
* Performs any scheduled fixed-rate updates followed by a single variable-rate update. | |||
* | |||
* @warning Both the fixed-rate and variable-rate update callbacks must be valid when calling `tick()`. | |||
*/ | |||
void tick(); | |||
/** | |||
* Resets the accumulated time (`at`) and frame timer, but not the elapsed fixed-rate update time. | |||
*/ | |||
void refresh() noexcept; | |||
/** | |||
* Resets the elapsed fixed-rate update time (`t`), accumulated time (`at`), and frame timer. | |||
*/ | |||
void reset() noexcept; | |||
/** | |||
* Sets the interval (`dt`) at which fixed-rate updates are scheduled. | |||
* | |||
* @param interval Fixed-rate update interval. | |||
*/ | |||
inline void set_fixed_update_interval(duration_type interval) noexcept | |||
{ | |||
m_fixed_update_interval = interval; | |||
} | |||
/** | |||
* Sets the minimum frame duration. If a frame is quicker than the minimum frame duration, the CPU will be idled until the minimum frame duration is met. | |||
* | |||
* @param duration Minimum frame duration. | |||
*/ | |||
inline void set_min_frame_duration(duration_type duration) noexcept | |||
{ | |||
m_min_frame_duration = duration; | |||
} | |||
/** | |||
* Sets the maximum accumulated frame duration. Prevents a "spiral of death", in which updates are scheduled too many times per frame while trying to catch up to the target update rate. | |||
* | |||
* @param duration Maximum accumulated frame duration. | |||
*/ | |||
inline void set_max_frame_duration(duration_type duration) noexcept | |||
{ | |||
m_max_frame_duration = duration; | |||
} | |||
/** | |||
* Sets the fixed-rate update callback. | |||
* | |||
* @param callback Fixed-rate update callback. | |||
*/ | |||
/// @{ | |||
inline void set_fixed_update_callback(fixed_update_callback_type&& callback) noexcept | |||
{ | |||
m_fixed_update_callback = callback; | |||
} | |||
inline void set_fixed_update_callback(const fixed_update_callback_type& callback) noexcept | |||
{ | |||
m_fixed_update_callback = callback; | |||
} | |||
/// @} | |||
/** | |||
* Sets the variable-rate update callback. | |||
* | |||
* @param callback Variable-rate update callback. | |||
*/ | |||
/// @{ | |||
inline void set_variable_update_callback(variable_update_callback_type&& callback) noexcept | |||
{ | |||
m_variable_update_callback = callback; | |||
} | |||
inline void set_variable_update_callback(const variable_update_callback_type& callback) noexcept | |||
{ | |||
m_variable_update_callback = callback; | |||
} | |||
/// @} | |||
/// Returns the elapsed fixed-rate update time (`t`). | |||
[[nodiscard]] inline duration_type get_fixed_update_time() const noexcept | |||
{ | |||
return m_fixed_update_time; | |||
} | |||
/// Returns the accumulated time (`at`). | |||
[[nodiscard]] inline duration_type get_accumulated_time() const noexcept | |||
{ | |||
return m_accumulated_time; | |||
} | |||
/// Returns the duration of the previous frame. | |||
[[nodiscard]] inline duration_type get_frame_duration() const noexcept | |||
{ | |||
return m_frame_duration; | |||
} | |||
/// Returns the minimum frame duration. | |||
[[nodiscard]] inline duration_type get_min_frame_duration() const noexcept | |||
{ | |||
return m_min_frame_duration; | |||
} | |||
/// Returns the maximum frame duration. | |||
[[nodiscard]] inline duration_type get_max_frame_duration() const noexcept | |||
{ | |||
return m_max_frame_duration; | |||
} | |||
/// Returns the fixed-rate update interval (`dt`). | |||
[[nodiscard]] inline duration_type get_fixed_update_interval() const noexcept | |||
{ | |||
return m_fixed_update_interval; | |||
} | |||
/// Returns the fixed-rate update callback. | |||
[[nodiscard]] inline const fixed_update_callback_type& get_fixed_update_callback() const noexcept | |||
{ | |||
return m_fixed_update_callback; | |||
} | |||
/// Returns the variable-rate update callback. | |||
[[nodiscard]] inline const variable_update_callback_type& get_variable_update_callback() const noexcept | |||
{ | |||
return m_variable_update_callback; | |||
} | |||
private: | |||
duration_type m_fixed_update_time{duration_type::zero()}; | |||
duration_type m_accumulated_time{duration_type::zero()}; | |||
time_point_type m_frame_start_time; | |||
time_point_type m_frame_end_time; | |||
duration_type m_frame_duration{duration_type::zero()}; | |||
duration_type m_min_frame_duration{duration_type::zero()}; | |||
duration_type m_max_frame_duration{duration_type::max()}; | |||
duration_type m_fixed_update_interval{duration_type::zero()}; | |||
fixed_update_callback_type m_fixed_update_callback; | |||
variable_update_callback_type m_variable_update_callback; | |||
}; | |||
#endif // ANTKEEPER_UTILITY_FRAME_SCHEDULER_HPP |
@ -0,0 +1,31 @@ | |||
/* | |||
* Copyright (C) 2023 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_GAME_RIGID_BODY_CONSTRAINT_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_RIGID_BODY_CONSTRAINT_COMPONENT_HPP | |||
#include <engine/physics/kinematics/constraint.hpp> | |||
#include <memory> | |||
struct rigid_body_constraint_component | |||
{ | |||
std::unique_ptr<physics::constraint> constraint; | |||
}; | |||
#endif // ANTKEEPER_GAME_RIGID_BODY_CONSTRAINT_COMPONENT_HPP |
@ -0,0 +1,34 @@ | |||
/* | |||
* Copyright (C) 2023 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_GAME_WINGED_LOCOMOTION_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_WINGED_LOCOMOTION_COMPONENT_HPP | |||
#include <engine/math/vector.hpp> | |||
/** | |||
* Winged aerial locomotion. | |||
*/ | |||
struct winged_locomotion_component | |||
{ | |||
/// Force vector. | |||
math::vector<float, 3> force{0.0f, 0.0f, 0.0f}; | |||
}; | |||
#endif // ANTKEEPER_GAME_WINGED_LOCOMOTION_COMPONENT_HPP |
@ -1,86 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 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/>. | |||
*/ | |||
#include "game/loop.hpp" | |||
#include <algorithm> | |||
loop::loop(): | |||
update_callback([](double, double){}), | |||
render_callback([](double){}), | |||
update_frequency(60.0), | |||
update_period(1.0 / update_frequency), | |||
max_frame_duration(update_period) | |||
{ | |||
reset(); | |||
} | |||
void loop::set_update_callback(std::function<void(double, double)> callback) | |||
{ | |||
update_callback = callback; | |||
} | |||
void loop::set_render_callback(std::function<void(double)> callback) | |||
{ | |||
render_callback = callback; | |||
} | |||
void loop::set_update_frequency(double frequency) | |||
{ | |||
update_frequency = frequency; | |||
update_period = 1.0 / update_frequency; | |||
} | |||
void loop::set_max_frame_duration(double duration) | |||
{ | |||
max_frame_duration = duration; | |||
} | |||
double loop::get_frame_duration() const | |||
{ | |||
return frame_duration; | |||
} | |||
void loop::reset() | |||
{ | |||
elapsed_time = 0.0; | |||
accumulator = 0.0; | |||
frame_start = std::chrono::high_resolution_clock::now(); | |||
frame_end = frame_start; | |||
frame_duration = 0.0; | |||
} | |||
void loop::tick() | |||
{ | |||
frame_end = std::chrono::high_resolution_clock::now(); | |||
frame_duration = static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(frame_end - frame_start).count()) / 1000000000.0; | |||
frame_start = frame_end; | |||
accumulator += std::min<double>(max_frame_duration, frame_duration); | |||
while (accumulator >= update_period) | |||
{ | |||
update_callback(elapsed_time, update_period); | |||
elapsed_time += update_period; | |||
accumulator -= update_period; | |||
} | |||
render_callback(accumulator * update_frequency); | |||
} | |||
@ -1,110 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 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_GAME_LOOP_HPP | |||
#define ANTKEEPER_GAME_LOOP_HPP | |||
#include <chrono> | |||
#include <functional> | |||
/** | |||
* Game loop with fixed timestep update calls and variable timestep render calls. | |||
* | |||
* @see https://gafferongames.com/post/fix_your_timestep/ | |||
*/ | |||
class loop | |||
{ | |||
public: | |||
loop(); | |||
/** | |||
* Sets the update callback. | |||
* | |||
* @param callback Function which takes two parameters: `t`, the total elapsed time, and `dt`, delta time (timestep) which is calculated as `1.0 / update_rate`. This function will be called at the frequency specified by `loop::set_update_rate()`. | |||
*/ | |||
void set_update_callback(std::function<void(double, double)> callback); | |||
/** | |||
* Sets the render callback. | |||
* | |||
* @param callback Function which takes one parameter: `alpha`, which is a factor that can be used to interpolate between the previous and current update states. | |||
*/ | |||
void set_render_callback(std::function<void(double)> callback); | |||
/** | |||
* Sets the update frequency. | |||
* | |||
* @param frequency Frequency, in hertz, at which the update callback should be called. | |||
*/ | |||
void set_update_frequency(double frequency); | |||
/** | |||
* Sets the maximum duration of a frame. This limits the number of times the update callback is called per frame, thereby preventing a "spiral of death", in which the update callback is called too many times per frame while trying to catch up to the target update rate. | |||
* | |||
* @param duration Maximum frame duration, in seconds.. | |||
*/ | |||
void set_max_frame_duration(double duration); | |||
/** | |||
* Returns the duration of the last frame, in seconds. | |||
*/ | |||
double get_frame_duration() const; | |||
/// Returns the frequency, in hertz, at which the update callback should be called. | |||
double get_update_frequency() const; | |||
/// Returns the period, in seconds, between update callback calls. | |||
double get_update_period() const; | |||
/** | |||
* Resets the total elapsed time, frame duration, and internal timers. | |||
*/ | |||
void reset(); | |||
/** | |||
* Updates the internal timers and performs the scheduled update and render callbacks. | |||
*/ | |||
void tick(); | |||
private: | |||
std::function<void(double, double)> update_callback; | |||
std::function<void(double)> render_callback; | |||
double update_frequency; | |||
double update_period; | |||
double max_frame_duration; | |||
double elapsed_time; | |||
double accumulator; | |||
std::chrono::high_resolution_clock::time_point frame_start; | |||
std::chrono::high_resolution_clock::time_point frame_end; | |||
double frame_duration; | |||
}; | |||
inline double loop::get_update_frequency() const | |||
{ | |||
return update_frequency; | |||
} | |||
inline double loop::get_update_period() const | |||
{ | |||
return update_period; | |||
} | |||
#endif // ANTKEEPER_GAME_LOOP_HPP |
@ -1,8 +1,9 @@ | |||
<?xml version="1.0"?> | |||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> | |||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> | |||
<windowsSettings> | |||
<ms_windowsSettings:dpiAware xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings" xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</ms_windowsSettings:dpiAware> | |||
</windowsSettings> | |||
</application> | |||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | |||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | |||
<asmv3:application> | |||
<asmv3:windowsSettings> | |||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> | |||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> | |||
</asmv3:windowsSettings> | |||
</asmv3:application> | |||
</assembly> |
@ -0,0 +1,38 @@ | |||
/* | |||
* Copyright (C) 2023 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/>. | |||
*/ | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
extern "C" | |||
{ | |||
/** | |||
* Requests NVIDIA Optimus to use high performance graphics. | |||
* | |||
* @see https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm | |||
*/ | |||
_declspec(dllexport) DWORD NvOptimusEnablement = 1; | |||
/** | |||
* Requests AMD PowerXpress to use high performance graphics. | |||
* | |||
* @see https://gpuopen.com/learn/amdpowerxpressrequesthighperformance/ | |||
*/ | |||
_declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; | |||
} |