Line data Source code
1 : /*
2 : * Copyright (C) 2025 aeml
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #pragma once
19 :
20 : #include "ecs/World.hpp"
21 : #include "physics/Components.hpp"
22 : #include "physics/CollisionSystem.hpp"
23 :
24 : #include <algorithm>
25 : #include <vector>
26 :
27 : namespace jobs { class JobSystem; }
28 :
29 : namespace physics
30 : {
31 : struct PhysicsSettings
32 : {
33 : int substeps{16};
34 : int positionIterations{20};
35 : int velocityIterations{10};
36 : int constraintIterations{8};
37 : float penetrationSlop{0.01f};
38 : float correctionPercent{0.2f};
39 : float maxPositionCorrection{0.2f};
40 : };
41 :
42 : // Resolves collisions by applying impulses.
43 : class CollisionResolutionSystem
44 : {
45 : public:
46 : struct SolverSettings
47 : {
48 : int positionIterations{16};
49 : int velocityIterations{8};
50 : float penetrationSlop{0.01f};
51 : float correctionPercent{0.2f};
52 : float maxCorrection{0.2f};
53 : };
54 :
55 79 : void SetSolverSettings(const SolverSettings& settings) { m_settings = settings; }
56 :
57 : // Resolve collisions for raw vectors (legacy/test usage)
58 : void Resolve(const std::vector<CollisionEvent>& events,
59 : std::vector<TransformComponent>& transforms,
60 : std::vector<RigidBodyComponent>& bodies) const;
61 :
62 : // Resolve collisions for ECS world
63 : void Resolve(const std::vector<CollisionEvent>& events, ecs::World& world) const;
64 :
65 : void ResolvePosition(const std::vector<CollisionEvent>& events, ecs::World& world, jobs::JobSystem* jobSystem = nullptr) const;
66 : void ResolveVelocity(const std::vector<CollisionEvent>& events, ecs::World& world, jobs::JobSystem* jobSystem = nullptr) const;
67 :
68 : private:
69 : SolverSettings m_settings{};
70 : };
71 :
72 : // Resolves constraints (joints).
73 : class ConstraintResolutionSystem
74 : {
75 : public:
76 : void Resolve(ecs::World& world, float dt) const;
77 79 : void SetIterationCount(int iterations) { m_iterations = std::max(1, iterations); }
78 : int IterationCount() const noexcept { return m_iterations; }
79 :
80 : private:
81 : int m_iterations{8};
82 : };
83 :
84 : // Integrates rigid bodies into transforms applying gravity / environment forces.
85 : class PhysicsIntegrationSystem : public ecs::ISystem
86 : {
87 : public:
88 : void Update(ecs::World& world, float dt) override; // Placeholder for future ECS usage.
89 : void UpdateVelocities(ecs::World& world, float dt);
90 :
91 : void Integrate(std::vector<TransformComponent>& transforms,
92 : std::vector<RigidBodyComponent>& bodies,
93 : float dt) const;
94 :
95 : float Gravity() const noexcept { return m_env.gravityY; }
96 :
97 33 : void SetEnvironment(const EnvironmentForces& env) { m_env = env; }
98 : const EnvironmentForces& Environment() const noexcept { return m_env; }
99 :
100 36 : void SetJobSystem(jobs::JobSystem* jobSystem) { m_jobSystem = jobSystem; }
101 :
102 : private:
103 : EnvironmentForces m_env{};
104 : jobs::JobSystem* m_jobSystem{nullptr};
105 : };
106 :
107 : // Orchestrates the entire physics pipeline: Integration -> Detection -> Resolution
108 : class PhysicsSystem : public ecs::ISystem
109 : {
110 : public:
111 : PhysicsSystem();
112 : void Update(ecs::World& world, float dt) override;
113 :
114 : void SetSettings(const PhysicsSettings& settings);
115 : const PhysicsSettings& Settings() const noexcept { return m_settings; }
116 :
117 33 : void SetEnvironment(const EnvironmentForces& env) { m_integration.SetEnvironment(env); }
118 34 : void SetJobSystem(jobs::JobSystem* js) { m_jobSystem = js; m_integration.SetJobSystem(js); }
119 :
120 26 : const std::vector<CollisionEvent>& GetCollisionEvents() const { return m_events; }
121 :
122 : private:
123 : void ApplySettings();
124 :
125 : PhysicsIntegrationSystem m_integration;
126 : CollisionSystem m_collision;
127 : CollisionResolutionSystem m_resolution;
128 : ConstraintResolutionSystem m_constraints;
129 : std::vector<CollisionEvent> m_events;
130 :
131 : // Broadphase buffers
132 : std::vector<AABBComponent> m_broadphaseAABBs;
133 : std::vector<std::uint32_t> m_broadphaseIds;
134 :
135 : jobs::JobSystem* m_jobSystem{nullptr};
136 : PhysicsSettings m_settings{};
137 : };
138 : }
|