forked from Themaister/Granite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphysics_system.hpp
292 lines (248 loc) · 8.13 KB
/
physics_system.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/* Copyright (c) 2017-2023 Hans-Kristian Arntzen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "scene.hpp"
#include "object_pool.hpp"
#include "math.hpp"
#include "ecs.hpp"
#include "global_managers_interface.hpp"
#include <memory>
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
struct btDbvtBroadphase;
class btSequentialImpulseConstraintSolver;
class btDiscreteDynamicsWorld;
class btCollisionShape;
class btBvhTriangleMeshShape;
class btTriangleIndexVertexArray;
class btGhostPairCallback;
class btDynamicsWorld;
namespace Granite
{
struct PhysicsHandle;
struct PhysicsComponent : ComponentBase
{
GRANITE_COMPONENT_TYPE_DECL(PhysicsComponent)
PhysicsHandle *handle = nullptr;
~PhysicsComponent();
};
struct CollisionMeshComponent : ComponentBase
{
GRANITE_COMPONENT_TYPE_DECL(CollisionMeshComponent)
SceneFormats::CollisionMesh mesh;
};
struct ForceComponent : ComponentBase
{
GRANITE_COMPONENT_TYPE_DECL(ForceComponent)
vec3 linear_force = vec3(0.0f);
vec3 torque = vec3(0.0f);
};
class KinematicCharacter
{
public:
KinematicCharacter();
KinematicCharacter(btDynamicsWorld *world, NodeHandle node);
~KinematicCharacter();
KinematicCharacter(KinematicCharacter &&other) noexcept;
KinematicCharacter &operator=(KinematicCharacter &&other) noexcept;
void set_move_velocity(const vec3 &v);
bool is_grounded();
void jump(const vec3 &v);
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
class CollisionEvent : public Event
{
public:
GRANITE_EVENT_TYPE_DECL(CollisionEvent)
CollisionEvent(Entity *entity0_, Entity *entity1_,
PhysicsHandle *object0_, PhysicsHandle *object1_,
const vec3 &world_point_, const vec3 &normal_)
: entity0(entity0_), entity1(entity1_),
object0(object0_), object1(object1_),
world_point(world_point_), normal(normal_)
{
}
Entity *get_first_entity() const
{
return entity0;
}
Entity *get_second_entity() const
{
return entity1;
}
PhysicsHandle *get_first_handle() const
{
return object0;
}
PhysicsHandle *get_second_handle() const
{
return object1;
}
vec3 get_world_contact() const
{
return world_point;
}
vec3 get_world_normal() const
{
return normal;
}
private:
Entity *entity0;
Entity *entity1;
PhysicsHandle *object0;
PhysicsHandle *object1;
vec3 world_point;
vec3 normal;
};
struct RaycastResult
{
Entity *entity;
PhysicsHandle *handle;
vec3 world_pos;
vec3 world_normal;
float t;
};
class PhysicsSystem final : public PhysicsSystemInterface
{
public:
PhysicsSystem();
~PhysicsSystem();
void set_scene(Scene *scene);
enum class InteractionType
{
Ghost,
Area,
Static,
Dynamic,
Kinematic
};
struct MaterialInfo
{
InteractionType type = InteractionType::Dynamic;
float mass = 1.0f;
float restitution = 0.5f;
float linear_damping = 0.1f;
float angular_damping = 0.1f;
float friction = 0.2f;
float rolling_friction = 0.2f;
float margin = 0.01f;
};
struct CollisionMesh
{
unsigned num_triangles = 0;
unsigned num_attributes = 0;
const uint32_t *indices = nullptr;
size_t index_stride_triangle = 0;
const float *positions = nullptr;
size_t position_stride = 0;
AABB aabb = {};
float margin = 0.1f;
};
unsigned register_collision_mesh(const CollisionMesh &mesh);
enum class MeshType
{
None,
ConvexHull,
Cube,
Sphere,
Cone,
Capsule,
Cylinder
};
struct ConvexMeshPart
{
MeshType type = MeshType::None;
const Node *child_node = nullptr;
unsigned index = 0;
float height = 1.0f;
float radius = 1.0f;
};
PhysicsHandle *add_compound_object(Node *node,
const ConvexMeshPart *parts, unsigned num_parts,
const MaterialInfo &info);
PhysicsHandle *add_object(Node *node,
const ConvexMeshPart &part,
const MaterialInfo &info);
PhysicsHandle *add_mesh(Node *node, unsigned index, const MaterialInfo &info);
PhysicsHandle *add_convex_hull(Node *node, unsigned index, const MaterialInfo &info);
PhysicsHandle *add_cube(Node *node, const MaterialInfo &info);
PhysicsHandle *add_sphere(Node *node, const MaterialInfo &info);
PhysicsHandle *add_cone(Node *node, float height, float radius, const MaterialInfo &info);
PhysicsHandle *add_capsule(Node *node, float height, float radius, const MaterialInfo &info);
PhysicsHandle *add_cylinder(Node *node, float height, float radius, const MaterialInfo &info);
PhysicsHandle *add_infinite_plane(const vec4 &plane, const MaterialInfo &info);
KinematicCharacter add_kinematic_character(NodeHandle node);
void set_linear_velocity(PhysicsHandle *handle, const vec3 &v);
void set_angular_velocity(PhysicsHandle *handle, const vec3 &v);
// Prefer ForceComponent.
void apply_force(PhysicsHandle *handle, const vec3 &v);
void apply_force(PhysicsHandle *handle, const vec3 &v, const vec3 &world_pos);
void remove_body(PhysicsHandle *handle);
static void set_handle_parent(PhysicsHandle *handle, Entity *entity);
static Entity *get_handle_parent(PhysicsHandle *handle);
static Node *get_scene_node(PhysicsHandle *handle);
static InteractionType get_interaction_type(PhysicsHandle *handle);
void apply_impulse(PhysicsHandle *handle, const vec3 &impulse, const vec3 &world_position);
void iterate(double frame_time);
void tick_callback(float tick_time);
enum InteractionTypeFlagBits
{
INTERACTION_TYPE_STATIC_BIT = 1 << 0,
INTERACTION_TYPE_DYNAMIC_BIT = 1 << 1,
INTERACTION_TYPE_INVISIBLE_BIT = 1 << 2,
INTERACTION_TYPE_KINEMATIC_BIT = 1 << 3,
INTERACTION_TYPE_ALL_BITS = 0x7fffffff
};
using InteractionTypeFlags = uint32_t;
RaycastResult query_closest_hit_ray(const vec3 &from, const vec3 &dir, float length,
InteractionTypeFlags mask = INTERACTION_TYPE_ALL_BITS);
void add_point_constraint(PhysicsHandle *handle, const vec3 &local_pivot);
void add_point_constraint(PhysicsHandle *handle0, PhysicsHandle *handle1,
const vec3 &local_pivot0, const vec3 &local_pivot1,
bool skip_collision = false);
enum class OverlapMethod
{
Broadphase,
Nearphase
};
bool get_overlapping_objects(PhysicsHandle *handle, std::vector<PhysicsHandle *> &other,
OverlapMethod method = OverlapMethod::Nearphase);
private:
std::unique_ptr<btDefaultCollisionConfiguration> collision_config;
std::unique_ptr<btCollisionDispatcher> dispatcher;
std::unique_ptr<btDbvtBroadphase> broadphase;
std::unique_ptr<btSequentialImpulseConstraintSolver> solver;
std::unique_ptr<btDiscreteDynamicsWorld> world;
Util::ObjectPool<PhysicsHandle> handle_pool;
std::vector<PhysicsHandle *> handles;
PhysicsHandle *add_shape(Node *node, const MaterialInfo &info, btCollisionShape *shape);
std::vector<CollisionEvent> new_collision_buffer;
std::vector<std::unique_ptr<btBvhTriangleMeshShape>> mesh_collision_shapes;
std::vector<std::unique_ptr<btTriangleIndexVertexArray>> index_vertex_arrays;
std::unique_ptr<btGhostPairCallback> ghost_callback;
btCollisionShape *create_shape(const ConvexMeshPart &part);
Scene *scene = nullptr;
const ComponentGroupVector<PhysicsComponent, ForceComponent> *forces = nullptr;
};
}